From 932282e638902621fd40d297c840dbf175ca8885 Mon Sep 17 00:00:00 2001 From: Filip Sekulic Date: Mon, 27 Feb 2023 17:20:22 +0100 Subject: [PATCH 01/19] What's new - OpenSea security provider (#16831) --- app/_locales/en/messages.json | 21 +++ app/images/open-sea-security-provider.svg | 91 +++++++++++++ app/scripts/controllers/preferences.js | 11 ++ app/scripts/controllers/preferences.test.js | 24 ++++ app/scripts/metamask-controller.js | 4 + test/e2e/fixture-builder.js | 2 + .../app/open-sea-whats-new-popover/index.js | 1 + .../app/open-sea-whats-new-popover/index.scss | 6 + .../open-sea-whats-new-popover.js | 124 ++++++++++++++++++ ui/pages/home/home.component.js | 2 + ui/selectors/selectors.js | 6 + ui/store/actions.ts | 16 ++- 12 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 app/images/open-sea-security-provider.svg create mode 100644 ui/components/app/open-sea-whats-new-popover/index.js create mode 100644 ui/components/app/open-sea-whats-new-popover/index.scss create mode 100644 ui/components/app/open-sea-whats-new-popover/open-sea-whats-new-popover.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 3cd6aa7721a1..f7845b79bf0d 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -329,6 +329,9 @@ "message": "Allow $1 to withdraw and spend up to the following amount:", "description": "The url of the site that requested permission to 'withdraw and spend'" }, + "alwaysBeSureTo": { + "message": "Always be sure to do your own due diligence before approving any requests." + }, "amount": { "message": "Amount" }, @@ -1266,6 +1269,9 @@ "enableOpenSeaAPIDescription": { "message": "Use OpenSea's API to fetch NFT data. NFT auto-detection relies on OpenSea's API, and will not be available when this is turned off." }, + "enableOpenSeaSecurityProvider": { + "message": "Enable security provider" + }, "enableSmartTransactions": { "message": "Enable smart transactions" }, @@ -1567,6 +1573,9 @@ "message": "Get Ether from a faucet for the $1 network.", "description": "Displays network name for Ether faucet" }, + "getWarningsFromOpenSea": { + "message": "Get warnings from OpenSea whenever you receive a known malicious request." + }, "goBack": { "message": "Go back" }, @@ -2327,6 +2336,9 @@ "notEnoughGas": { "message": "Not enough gas" }, + "notNow": { + "message": "Not now" + }, "notifications": { "message": "Notifications" }, @@ -2660,6 +2672,12 @@ "openSea": { "message": "OpenSea (Beta)" }, + "openSeaAltText": { + "message": "OpenSea security provider" + }, + "openSeaDescription": { + "message": "OpenSea is the first security provider for this feature. More providers coming soon!" + }, "openSeaNew": { "message": "OpenSea" }, @@ -3561,6 +3579,9 @@ "statusNotConnected": { "message": "Not connected" }, + "staySafeWithOpenSea": { + "message": "Stay safe with OpenSea" + }, "step1LatticeWallet": { "message": "Connect your Lattice1" }, diff --git a/app/images/open-sea-security-provider.svg b/app/images/open-sea-security-provider.svg new file mode 100644 index 000000000000..ac79c0026adb --- /dev/null +++ b/app/images/open-sea-security-provider.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index ab51bb0c5bb6..b0afa083b413 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -70,6 +70,7 @@ export default class PreferencesController { : LedgerTransportTypes.u2f, transactionSecurityCheckEnabled: false, theme: ThemeType.os, + openSeaTransactionSecurityProviderPopoverHasBeenShown: false, ...opts.initState, }; @@ -206,6 +207,16 @@ export default class PreferencesController { }); } + /** + * Setter for the `openSeaTransactionSecurityProviderPopoverHasBeenShown` property + * + */ + setOpenSeaTransactionSecurityProviderPopoverHasBeenShown() { + this.store.updateState({ + openSeaTransactionSecurityProviderPopoverHasBeenShown: true, + }); + } + /** * Add new methodData to state, to avoid requesting this information again through Infura * diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index 7c4e2d1107e6..1679cab45f96 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -390,4 +390,28 @@ describe('preferences controller', function () { ); }); }); + + describe('setOpenSeaTransactionSecurityProviderPopoverHasBeenShown', function () { + it('should default to value "false"', function () { + const state = preferencesController.store.getState(); + assert.equal( + state.openSeaTransactionSecurityProviderPopoverHasBeenShown, + false, + ); + }); + + it('should set the openSeaTransactionSecurityProviderPopoverHasBeenShown to true', function () { + const state = preferencesController.store.getState(); + assert.equal( + state.openSeaTransactionSecurityProviderPopoverHasBeenShown, + false, + ); + preferencesController.setOpenSeaTransactionSecurityProviderPopoverHasBeenShown(); + assert.equal( + preferencesController.store.getState() + .openSeaTransactionSecurityProviderPopoverHasBeenShown, + true, + ); + }); + }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 9309d1eb8151..73578b8348c4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1865,6 +1865,10 @@ export default class MetamaskController extends EventEmitter { preferencesController.setTransactionSecurityCheckEnabled.bind( preferencesController, ), + setOpenSeaTransactionSecurityProviderPopoverHasBeenShown: + preferencesController.setOpenSeaTransactionSecurityProviderPopoverHasBeenShown.bind( + preferencesController, + ), // AssetsContractController getTokenStandardAndDetails: this.getTokenStandardAndDetails.bind(this), diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 7ec760bcf474..3e0c6921f2ff 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -234,6 +234,7 @@ function defaultFixture() { useTokenDetection: false, useCurrencyRateCheck: true, useMultiAccountBalanceChecker: true, + openSeaTransactionSecurityProviderPopoverHasBeenShown: true, }, SmartTransactionsController: { smartTransactionsState: { @@ -346,6 +347,7 @@ function onboardingFixture() { useTokenDetection: false, useCurrencyRateCheck: true, useMultiAccountBalanceChecker: true, + openSeaTransactionSecurityProviderPopoverHasBeenShown: true, }, SmartTransactionsController: { smartTransactionsState: { diff --git a/ui/components/app/open-sea-whats-new-popover/index.js b/ui/components/app/open-sea-whats-new-popover/index.js new file mode 100644 index 000000000000..abd91185ed53 --- /dev/null +++ b/ui/components/app/open-sea-whats-new-popover/index.js @@ -0,0 +1 @@ +export { default } from './open-sea-whats-new-popover'; diff --git a/ui/components/app/open-sea-whats-new-popover/index.scss b/ui/components/app/open-sea-whats-new-popover/index.scss new file mode 100644 index 000000000000..ff307b957902 --- /dev/null +++ b/ui/components/app/open-sea-whats-new-popover/index.scss @@ -0,0 +1,6 @@ +.open-sea-whats-new-popover { + &__enable-security-provider-button { + width: fit-content; + font-weight: 400; + } +} diff --git a/ui/components/app/open-sea-whats-new-popover/open-sea-whats-new-popover.js b/ui/components/app/open-sea-whats-new-popover/open-sea-whats-new-popover.js new file mode 100644 index 000000000000..30bfda33a30f --- /dev/null +++ b/ui/components/app/open-sea-whats-new-popover/open-sea-whats-new-popover.js @@ -0,0 +1,124 @@ +import React, { useContext } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; +import { I18nContext } from '../../../contexts/i18n'; +import Popover from '../../ui/popover'; +import { + DISPLAY, + FLEX_DIRECTION, + FONT_WEIGHT, + TextColor, + TextVariant, +} from '../../../helpers/constants/design-system'; +import Button from '../../ui/button'; +import Box from '../../ui/box'; +import { + setOpenSeaTransactionSecurityProviderPopoverHasBeenShown, + setTransactionSecurityCheckEnabled, +} from '../../../store/actions'; +import { getHasTheOpenSeaTransactionSecurityProviderPopoverBeenShown } from '../../../selectors'; +import { Text } from '../../component-library'; +import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes'; + +export default function OpenSeaWhatsNewPopover() { + const t = useContext(I18nContext); + const dispatch = useDispatch(); + const history = useHistory(); + + const hasThePopoverBeenShown = useSelector( + getHasTheOpenSeaTransactionSecurityProviderPopoverBeenShown, + ); + + return ( + process.env.TRANSACTION_SECURITY_PROVIDER && + !hasThePopoverBeenShown && ( + + {t('staySafeWithOpenSea')} + + } + footer={ + <> + + + + + + + + } + footerClassName="smart-transactions-popover__footer" + className="smart-transactions-popover" + onClose={() => + dispatch(setOpenSeaTransactionSecurityProviderPopoverHasBeenShown()) + } + > + + + {t('openSeaAltText')} + + + {t('getWarningsFromOpenSea')} + + + {t('openSeaDescription')} + + + {t('alwaysBeSureTo')} + + + + ) + ); +} diff --git a/ui/pages/home/home.component.js b/ui/pages/home/home.component.js index b0b7c23f28c1..3b5f62170f5c 100644 --- a/ui/pages/home/home.component.js +++ b/ui/pages/home/home.component.js @@ -49,6 +49,7 @@ import { ONBOARDING_SECURE_YOUR_WALLET_ROUTE, } from '../../helpers/constants/routes'; import ZENDESK_URLS from '../../helpers/constants/zendesk-url'; +import OpenSeaWhatsNewPopover from '../../components/app/open-sea-whats-new-popover/open-sea-whats-new-popover'; ///: BEGIN:ONLY_INCLUDE_IN(main) import { SUPPORT_LINK } from '../../../shared/lib/ui-utils'; ///: END:ONLY_INCLUDE_IN @@ -638,6 +639,7 @@ export default class Home extends PureComponent { />
{showWhatsNew ? : null} + {showWhatsNew ? : null} {!showWhatsNew && showRecoveryPhraseReminder ? ( { - return async () => { + return async (dispatch) => { try { await submitRequestToBackground('setTransactionSecurityCheckEnabled', [ transactionSecurityCheckEnabled, ]); + await forceUpdateMetamaskState(dispatch); } catch (error) { logErrorWithMessage(error); } @@ -4511,6 +4512,19 @@ export function setFirstTimeUsedNetwork(chainId: string) { return submitRequestToBackground('setFirstTimeUsedNetwork', [chainId]); } +export function setOpenSeaTransactionSecurityProviderPopoverHasBeenShown(): ThunkAction< + void, + MetaMaskReduxState, + unknown, + AnyAction +> { + return async () => { + await submitRequestToBackground( + 'setOpenSeaTransactionSecurityProviderPopoverHasBeenShown', + ); + }; +} + // QR Hardware Wallets export async function submitQRHardwareCryptoHDKey(cbor: Hex) { await submitRequestToBackground('submitQRHardwareCryptoHDKey', [cbor]); From 64bfe6f3076b5cff9b6dbcee15020bbfd7ce123a Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 27 Feb 2023 17:32:51 +0100 Subject: [PATCH 02/19] Fix a bug where non-address types would be rendered as addresses in EIP-712 (#17846) * Fix EIP-712 rendering logic * Fix tests * Fix tests and story * Fix lint * Fix import * Fix stories --- .../signature-request-data.js | 5 +- .../signature-request-data.stories.js | 85 ++-- .../signature-request-data.test.js | 316 ++++----------- .../signature-request-message.js | 2 +- .../signature-request-message.stories.js | 83 ++-- ui/helpers/utils/util.js | 17 +- ui/helpers/utils/util.test.js | 370 ++++++++++++++++-- 7 files changed, 542 insertions(+), 336 deletions(-) diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.js index a809d4a65dd8..82932a1de50b 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.js @@ -26,7 +26,7 @@ function SignatureRequestData({ data }) { return ( - {Object.entries(data).map(([label, value], i) => ( + {Object.entries(data).map(([label, { value, type }], i) => ( - {isValidHexAddress(value, { + {type === 'address' && + isValidHexAddress(value, { mixedCaseUseChecksum: true, }) ? ( { DefaultStory.storyName = 'Default'; -DefaultStory.args = { - data: JSON.parse( - JSON.stringify({ - domain: { - name: 'happydapp.website', - }, - message: { - string: 'haay wuurl', - number: 42, - }, - primaryType: 'Mail', - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Group: [ - { name: 'name', type: 'string' }, - { name: 'members', type: 'Person[]' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person[]' }, - { name: 'contents', type: 'string' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallets', type: 'address[]' }, +const rawMessage = { + domain: { + chainId: 97, + name: 'Ether Mail', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + '0x06195827297c7A80a443b6894d3BDB8824b43896', + ], + }, + to: [ + { + name: 'Bob', + wallets: [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', ], }, - }), - ), + ], + }, + primaryType: 'Mail', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + }, +}; + +DefaultStory.args = { + data: sanitizeMessage( + rawMessage.message, + rawMessage.primaryType, + rawMessage.types, + ).value, }; diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js index 9ea93fe0546a..c6fabe549c8f 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js @@ -1,6 +1,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import { sanitizeMessage } from '../../../../helpers/utils/util'; import Identicon from '../../../ui/identicon'; import SignatureRequestData from './signature-request-data'; @@ -59,124 +60,65 @@ describe('Signature Request Data', () => { }, }; - let messageData; const store = configureMockStore()(mockStore); - beforeEach(() => { - messageData = { - domain: { - chainId: 97, - name: 'Ether Mail', - verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', - version: '1', + const rawMessage = { + domain: { + chainId: 97, + name: 'Ether Mail', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + '0x06195827297c7A80a443b6894d3BDB8824b43896', + ], }, - message: { - contents: 'Hello, Bob!', - from: { - name: 'Cow', + to: [ + { + name: 'Bob', wallets: [ - '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', - '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', - '0x06195827297c7A80a443b6894d3BDB8824b43896', + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', ], }, - to: [ - { - name: 'Bob', - wallets: [ - '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', - '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', - '0xB0B0b0b0b0b0B000000000000000000000000000', - ], - }, - ], - }, - primaryType: 'Mail', - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person[]' }, - { name: 'contents', type: 'string' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallets', type: 'address[]' }, - ], - }, - }; - }); - - it('should render domain chainId', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; - const { getByText } = renderWithProvider( - , - store, - ); - - expect(getByText('97')).toBeInTheDocument(); - }); - - it('should render domain name', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; - const { getByText } = renderWithProvider( - , - store, - ); - - expect(getByText('Ether Mail')).toBeInTheDocument(); - }); - - it('should render Identicon for domain verifying contract', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; - const iconImage = ( - - ); - expect(iconImage).toBeDefined(); - }); - - it('should render domain verifying contract shorten address', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; - const { getByText } = renderWithProvider( - , - store, - ); + ], + }, + primaryType: 'Mail', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + }, + }; - expect(getByText('0xCcC...cccC')).toBeInTheDocument(); - }); + const messageData = sanitizeMessage( + rawMessage.message, + rawMessage.primaryType, + rawMessage.types, + ); it('should render contents title', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -184,13 +126,8 @@ describe('Signature Request Data', () => { }); it('should render contants text', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -198,13 +135,8 @@ describe('Signature Request Data', () => { }); it('should render from title', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -212,13 +144,8 @@ describe('Signature Request Data', () => { }); it('should render name title in "from" object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -226,13 +153,8 @@ describe('Signature Request Data', () => { }); it('should render name text in "from" object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -240,13 +162,8 @@ describe('Signature Request Data', () => { }); it('should render wallets title in "from" object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -254,28 +171,18 @@ describe('Signature Request Data', () => { }); it('should render Identicon for first wallet in "from" object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const iconImage = ( ); expect(iconImage).toBeDefined(); }); it('should render first account name from wallets array if address exists in identities object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -283,28 +190,18 @@ describe('Signature Request Data', () => { }); it('should render Identicon for second wallet in "from" object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const iconImage = ( ); expect(iconImage).toBeDefined(); }); it('should render second account name from wallets array if address exists in identities object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -312,28 +209,18 @@ describe('Signature Request Data', () => { }); it('should render Identicon for third wallet in "from" object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const iconImage = ( ); expect(iconImage).toBeDefined(); }); it('should render third account name from wallets array if address exists in address book object', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -341,13 +228,8 @@ describe('Signature Request Data', () => { }); it('should render name title in "to" array of objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -355,13 +237,8 @@ describe('Signature Request Data', () => { }); it('should render name text in "to" array of objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -369,13 +246,8 @@ describe('Signature Request Data', () => { }); it('should render wallets title in "to" array of objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -383,28 +255,18 @@ describe('Signature Request Data', () => { }); it('should render Identicon for first wallet in "to" array of objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const iconImage = ( ); expect(iconImage).toBeDefined(); }); it('should render first shorten address from wallets array if address does not exists in identities and address book objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -412,28 +274,18 @@ describe('Signature Request Data', () => { }); it('should render Identicon for second wallet in "to" array of objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const iconImage = ( ); expect(iconImage).toBeDefined(); }); it('should render second shorten address from wallets array if address does not exists in identities and address book objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -441,28 +293,18 @@ describe('Signature Request Data', () => { }); it('should render Identicon for third wallet in "to" array of objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const iconImage = ( ); expect(iconImage).toBeDefined(); }); it('should render third shorten address from wallets array if address does not exists in identities and address book objects', () => { - const msgParams = { - data: JSON.parse(JSON.stringify(messageData)), - version: 'V4', - origin: 'test', - }; const { getByText } = renderWithProvider( - , + , store, ); @@ -471,9 +313,9 @@ describe('Signature Request Data', () => { it('should escape RTL character in label or value', () => { const messageDataWithRTLCharacters = { - ...messageData, + ...rawMessage, message: { - ...messageData.message, + ...rawMessage.message, contents: 'Hello, \u202E Bob!', from: { 'name\u202Ename': 'Cow \u202E Cow', @@ -495,20 +337,20 @@ describe('Signature Request Data', () => { ], }, types: { - ...messageData.message.types, + ...rawMessage.types, Person: [ { name: 'name\u202Ename', type: 'string' }, { name: 'wallets\u202Ewallets', type: 'address[]' }, ], }, }; - const msgParams = { - data: JSON.parse(JSON.stringify(messageDataWithRTLCharacters)), - version: 'V4', - origin: 'test', - }; + const data = sanitizeMessage( + messageDataWithRTLCharacters.message, + messageDataWithRTLCharacters.primaryType, + messageDataWithRTLCharacters.types, + ); const { getByText, getAllByText } = renderWithProvider( - , + , store, ); diff --git a/ui/components/app/signature-request/signature-request-message/signature-request-message.js b/ui/components/app/signature-request/signature-request-message/signature-request-message.js index e6ec5e422a79..d343a6584696 100644 --- a/ui/components/app/signature-request/signature-request-message/signature-request-message.js +++ b/ui/components/app/signature-request/signature-request-message/signature-request-message.js @@ -87,7 +87,7 @@ export default function SignatureRequestMessage({ > {primaryType} - + ); diff --git a/ui/components/app/signature-request/signature-request-message/signature-request-message.stories.js b/ui/components/app/signature-request/signature-request-message/signature-request-message.stories.js index af3c188d09a2..9449e33a5189 100644 --- a/ui/components/app/signature-request/signature-request-message/signature-request-message.stories.js +++ b/ui/components/app/signature-request/signature-request-message/signature-request-message.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import { sanitizeMessage } from '../../../../helpers/utils/util'; import SignatureRequestMessage from './signature-request-message'; export default { @@ -20,39 +21,59 @@ export const DefaultStory = (args) => { DefaultStory.storyName = 'Default'; -DefaultStory.args = { - data: JSON.parse( - JSON.stringify({ - domain: { - name: 'happydapp.website', - }, - message: { - string: 'haay wuurl', - number: 42, - }, - primaryType: 'Mail', - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Group: [ - { name: 'name', type: 'string' }, - { name: 'members', type: 'Person[]' }, - ], - Mail: [ - { name: 'from', type: 'Person' }, - { name: 'to', type: 'Person[]' }, - { name: 'contents', type: 'string' }, - ], - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallets', type: 'address[]' }, +const rawMessage = { + domain: { + chainId: 97, + name: 'Ether Mail', + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + '0x06195827297c7A80a443b6894d3BDB8824b43896', + ], + }, + to: [ + { + name: 'Bob', + wallets: [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', ], }, - }), + ], + }, + primaryType: 'Mail', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + }, +}; + +DefaultStory.args = { + data: sanitizeMessage( + rawMessage.message, + rawMessage.primaryType, + rawMessage.types, ), messageIsScrollable: true, }; diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js index eeef079bf0ef..487593220381 100644 --- a/ui/helpers/utils/util.js +++ b/ui/helpers/utils/util.js @@ -444,11 +444,14 @@ export const sanitizeMessage = (msg, primaryType, types) => { // Primary type can be an array. const isArray = primaryType && isArrayType(primaryType); if (isArray) { - return msg.map((value) => - sanitizeMessage(value, stripOneLayerofNesting(primaryType), types), - ); + return { + value: msg.map((value) => + sanitizeMessage(value, stripOneLayerofNesting(primaryType), types), + ), + type: primaryType, + }; } else if (isSolidityType(primaryType)) { - return msg; + return { value: msg, type: primaryType }; } // If not, assume to be struct @@ -459,7 +462,7 @@ export const sanitizeMessage = (msg, primaryType, types) => { throw new Error(`Invalid primary type definition`); } - const sanitizedMessage = {}; + const sanitizedStruct = {}; const msgKeys = Object.keys(msg); msgKeys.forEach((msgKey) => { const definedType = Object.values(baseTypeDefinitions).find( @@ -470,13 +473,13 @@ export const sanitizeMessage = (msg, primaryType, types) => { return; } - sanitizedMessage[msgKey] = sanitizeMessage( + sanitizedStruct[msgKey] = sanitizeMessage( msg[msgKey], definedType.type, types, ); }); - return sanitizedMessage; + return { value: sanitizedStruct, type: primaryType }; }; export function getAssetImageURL(image, ipfsGateway) { diff --git a/ui/helpers/utils/util.test.js b/ui/helpers/utils/util.test.js index 228d5840420b..704a31d6833c 100644 --- a/ui/helpers/utils/util.test.js +++ b/ui/helpers/utils/util.test.js @@ -478,12 +478,107 @@ describe('util', () => { it('should return parsed message if types is defined', () => { const result = util.sanitizeMessage(message, primaryType, types); - expect(result.contents).toStrictEqual('Hello, Bob!'); - expect(result.from.name).toStrictEqual('Cow'); - expect(result.from.wallets).toHaveLength(2); - expect(result.to).toHaveLength(1); - expect(result.to[0].name).toStrictEqual('Bob'); - expect(result.to[0].wallets).toHaveLength(3); + expect(result).toStrictEqual({ + type: 'Mail', + value: { + contents: { + type: 'string', + value: 'Hello, Bob!', + }, + from: { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Cow', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + { + type: 'address', + value: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + }, + ], + }, + }, + }, + nestArray: { + type: 'uint256[2][2]', + value: [ + { + type: 'uint256[2]', + value: [ + { + type: 'uint256', + value: 12, + }, + { + type: 'uint256', + value: 34, + }, + { + type: 'uint256', + value: 56, + }, + ], + }, + { + type: 'uint256[2]', + value: [ + { + type: 'uint256', + value: 56, + }, + { + type: 'uint256', + value: 78, + }, + { + type: 'uint256', + value: 89, + }, + ], + }, + ], + }, + to: { + type: 'Person[]', + value: [ + { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Bob', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + { + type: 'address', + value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + }, + { + type: 'address', + value: '0xB0B0b0b0b0b0B000000000000000000000000000', + }, + ], + }, + }, + }, + ], + }, + }, + }); }); it('should return parsed nested array if defined', () => { @@ -497,10 +592,50 @@ describe('util', () => { primaryType, types, ); - expect(result.nestArray).toHaveLength(2); - expect(result.nestArray[0]).toHaveLength(3); - expect(result.nestArray[0][0]).toStrictEqual(12); - expect(result.nestArray[0][2]).toStrictEqual(56); + expect(result).toStrictEqual({ + type: 'Mail', + value: { + nestArray: { + type: 'uint256[2][2]', + value: [ + { + type: 'uint256[2]', + value: [ + { + type: 'uint256', + value: 12, + }, + { + type: 'uint256', + value: 34, + }, + { + type: 'uint256', + value: 56, + }, + ], + }, + { + type: 'uint256[2]', + value: [ + { + type: 'uint256', + value: 56, + }, + { + type: 'uint256', + value: 78, + }, + { + type: 'uint256', + value: 89, + }, + ], + }, + ], + }, + }, + }); }); it('should return parsed nested array with struct if defined', () => { @@ -537,14 +672,104 @@ describe('util', () => { ], }; const result = util.sanitizeMessage(msg, primaryType, types); - expect(result.nestedPeople).toHaveLength(2); - expect(result.nestedPeople[0]).toHaveLength(1); - expect(result.nestedPeople[0][0].name).toStrictEqual('Bob'); - expect(result.nestedPeople[0][0].wallets).toHaveLength(3); - expect(result.nestedPeople[0][0].wallets[0]).toStrictEqual( - '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', - ); - expect(result.nestedPeople[1][1].name).toStrictEqual('Brandon'); + expect(result).toStrictEqual({ + type: 'Mail', + value: { + nestedPeople: { + type: 'Person[][]', + value: [ + { + type: 'Person[]', + value: [ + { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Bob', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + { + type: 'address', + value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + }, + { + type: 'address', + value: '0xB0B0b0b0b0b0B000000000000000000000000000', + }, + ], + }, + }, + }, + ], + }, + { + type: 'Person[]', + value: [ + { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Ben', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + { + type: 'address', + value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + }, + { + type: 'address', + value: '0xB0B0b0b0b0b0B000000000000000000000000000', + }, + ], + }, + }, + }, + { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Brandon', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + { + type: 'address', + value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + }, + { + type: 'address', + value: '0xB0B0b0b0b0b0B000000000000000000000000000', + }, + ], + }, + }, + }, + ], + }, + ], + }, + }, + }); }); it('should return ignore message data with unknown types', () => { @@ -555,14 +780,107 @@ describe('util', () => { // result will NOT contain the do_not_displays because type definition const result = util.sanitizeMessage(message, primaryType, types); - expect(result.contents).toStrictEqual('Hello, Bob!'); - expect(result.from.name).toStrictEqual('Cow'); - expect(result.from.wallets).toHaveLength(2); - expect(result.to).toHaveLength(1); - expect(result.to[0].name).toStrictEqual('Bob'); - expect(result.to[0].wallets).toHaveLength(3); - expect(result.do_not_display).toBeUndefined(); - expect(result.do_not_display_2).toBeUndefined(); + expect(result).toStrictEqual({ + type: 'Mail', + value: { + contents: { + type: 'string', + value: 'Hello, Bob!', + }, + from: { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Cow', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + }, + { + type: 'address', + value: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + }, + ], + }, + }, + }, + nestArray: { + type: 'uint256[2][2]', + value: [ + { + type: 'uint256[2]', + value: [ + { + type: 'uint256', + value: 12, + }, + { + type: 'uint256', + value: 34, + }, + { + type: 'uint256', + value: 56, + }, + ], + }, + { + type: 'uint256[2]', + value: [ + { + type: 'uint256', + value: 56, + }, + { + type: 'uint256', + value: 78, + }, + { + type: 'uint256', + value: 89, + }, + ], + }, + ], + }, + to: { + type: 'Person[]', + value: [ + { + type: 'Person', + value: { + name: { + type: 'string', + value: 'Bob', + }, + wallets: { + type: 'address[]', + value: [ + { + type: 'address', + value: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + }, + { + type: 'address', + value: '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + }, + { + type: 'address', + value: '0xB0B0b0b0b0b0B000000000000000000000000000', + }, + ], + }, + }, + }, + ], + }, + }, + }); }); }); }); From 63cbcc71479c6f03ad68556e7d03e0b5f91d0f12 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 27 Feb 2023 17:33:21 +0100 Subject: [PATCH 03/19] Selector performance improvements (#17410) * Stop checksumming addresses unnecesarily * Fix lint --- ui/selectors/selectors.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index a4f088250b0e..cf6632c26672 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -49,7 +49,6 @@ import { import { TEMPLATED_CONFIRMATION_MESSAGE_TYPES } from '../pages/confirmation/templates'; import { STATIC_MAINNET_TOKEN_LIST } from '../../shared/constants/tokens'; -import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; import { DAY } from '../../shared/constants/time'; import { getNativeCurrency, @@ -394,7 +393,7 @@ export function getEnsResolutionByAddress(state, address) { const entry = getAddressBookEntry(state, address) || Object.values(state.metamask.identities).find((identity) => - isEqualCaseInsensitive(identity.address, toChecksumHexAddress(address)), + isEqualCaseInsensitive(identity.address, address), ); return entry?.name || ''; @@ -403,7 +402,7 @@ export function getEnsResolutionByAddress(state, address) { export function getAddressBookEntry(state, address) { const addressBook = getAddressBook(state); const entry = addressBook.find((contact) => - isEqualCaseInsensitive(contact.address, toChecksumHexAddress(address)), + isEqualCaseInsensitive(contact.address, address), ); return entry; } @@ -412,14 +411,14 @@ export function getAddressBookEntryOrAccountName(state, address) { const entry = getAddressBookEntry(state, address) || Object.values(state.metamask.identities).find((identity) => - isEqualCaseInsensitive(identity.address, toChecksumHexAddress(address)), + isEqualCaseInsensitive(identity.address, address), ); return entry && entry.name !== '' ? entry.name : address; } export function getAccountName(identities, address) { const entry = Object.values(identities).find((identity) => - isEqualCaseInsensitive(identity.address, toChecksumHexAddress(address)), + isEqualCaseInsensitive(identity.address, address), ); return entry && entry.name !== '' ? entry.name : ''; } @@ -427,7 +426,7 @@ export function getAccountName(identities, address) { export function getMetadataContractName(state, address) { const tokenList = getTokenList(state); const entry = Object.values(tokenList).find((identity) => - isEqualCaseInsensitive(identity.address, toChecksumHexAddress(address)), + isEqualCaseInsensitive(identity.address, address), ); return entry && entry.name !== '' ? entry.name : ''; } @@ -840,9 +839,8 @@ export const getMemoizedMetadataContractName = createDeepEqualSelector( getTokenList, (_tokenList, address) => address, (tokenList, address) => { - const checksumHexAddress = toChecksumHexAddress(address); const entry = Object.values(tokenList).find((identity) => - isEqualCaseInsensitive(identity.address, checksumHexAddress), + isEqualCaseInsensitive(identity.address, address), ); return entry && entry.name !== '' ? entry.name : ''; }, From 5561987fed3d336383fd081b6c6770012d7b5bd3 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Mon, 27 Feb 2023 10:42:02 -0600 Subject: [PATCH 04/19] UX: Icon: Stop using fa-times (#17811) --- .../__snapshots__/beta-header.test.js.snap | 9 +- ui/components/app/beta-header/index.js | 13 ++- .../app/dropdowns/network-dropdown.js | 17 ++-- .../customize-nonce.component.js | 9 +- .../customize-nonce.stories.js | 10 +++ .../edit-approval-permission.component.js | 9 +- .../new-account-modal.component.js | 8 +- ui/components/ui/callout/callout.js | 9 +- ui/pages/add-nft/add-nft.js | 16 +++- ui/pages/add-nft/add-nft.test.js | 7 +- ui/pages/home/home.component.js | 36 +++++--- .../onboarding-flow/metametrics/index.scss | 6 -- .../metametrics/metametrics.js | 90 ++++++++++++------- .../add-recipient/domain-input.component.js | 16 ++-- .../custom-content-search.js | 9 +- .../settings-search/settings-search.js | 7 +- 16 files changed, 168 insertions(+), 103 deletions(-) create mode 100644 ui/components/app/modals/customize-nonce/customize-nonce.stories.js diff --git a/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap b/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap index 8c88f9bdc046..7190ad958c6d 100644 --- a/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap +++ b/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap @@ -3,7 +3,7 @@ exports[`Beta Header should match snapshot 1`] = `
diff --git a/ui/components/app/beta-header/index.js b/ui/components/app/beta-header/index.js index 7abb2eb3a22f..72dffa0062cf 100644 --- a/ui/components/app/beta-header/index.js +++ b/ui/components/app/beta-header/index.js @@ -8,10 +8,13 @@ import { Color, BLOCK_SIZES, DISPLAY, + AlignItems, + IconColor, } from '../../../helpers/constants/design-system'; import { BETA_BUGS_URL } from '../../../helpers/constants/beta'; import { hideBetaHeader } from '../../../store/actions'; +import { ButtonIcon, ICON_NAMES, ICON_SIZES } from '../../component-library'; const BetaHeader = () => { const t = useI18nContext(); @@ -23,6 +26,7 @@ const BetaHeader = () => { backgroundColor={Color.warningDefault} padding={2} className="beta-header" + alignItems={AlignItems.center} > { , ])} - + /> ); }; diff --git a/ui/components/app/dropdowns/network-dropdown.js b/ui/components/app/dropdowns/network-dropdown.js index f15bbe5afa82..d7f4cb77565b 100644 --- a/ui/components/app/dropdowns/network-dropdown.js +++ b/ui/components/app/dropdowns/network-dropdown.js @@ -22,8 +22,12 @@ import { ADD_POPULAR_CUSTOM_NETWORK, ADVANCED_ROUTE, } from '../../../helpers/constants/routes'; - -import { Icon, ICON_NAMES } from '../../component-library'; +import { + Icon, + ButtonIcon, + ICON_NAMES, + ICON_SIZES, +} from '../../component-library'; import { Dropdown, DropdownMenuItem } from './dropdown'; // classes from nodes of the toggle element. @@ -195,9 +199,12 @@ class NetworkDropdown extends Component { > {nickname || rpcUrl} - {isCurrentRpcTarget ? null : ( - { e.stopPropagation(); this.props.showConfirmDeleteNetworkModal({ diff --git a/ui/components/app/modals/customize-nonce/customize-nonce.component.js b/ui/components/app/modals/customize-nonce/customize-nonce.component.js index 16b9a25f19ea..9aa370eb9a67 100644 --- a/ui/components/app/modals/customize-nonce/customize-nonce.component.js +++ b/ui/components/app/modals/customize-nonce/customize-nonce.component.js @@ -15,6 +15,7 @@ import Box from '../../../ui/box'; import withModalProps from '../../../../helpers/higher-order-components/with-modal-props'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url'; +import { ButtonIcon, ICON_NAMES, ICON_SIZES } from '../../../component-library'; const CustomizeNonce = ({ hideModal, @@ -52,9 +53,11 @@ const CustomizeNonce = ({ > {t('editNonceField')} -
diff --git a/ui/components/app/modals/customize-nonce/customize-nonce.stories.js b/ui/components/app/modals/customize-nonce/customize-nonce.stories.js new file mode 100644 index 000000000000..b1a4e7bb1ace --- /dev/null +++ b/ui/components/app/modals/customize-nonce/customize-nonce.stories.js @@ -0,0 +1,10 @@ +import React from 'react'; +import CustomizeNonce from '.'; + +export default { + title: 'Components/App/Modals/CustomizeNonce', +}; + +export const DefaultStory = () => ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js index 8ab5a7330d5b..bb4552e54478 100644 --- a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js +++ b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js @@ -10,6 +10,7 @@ import { calcTokenAmount, toPrecisionWithoutTrailingZeros, } from '../../../../../shared/lib/transactions-controller-utils'; +import { ButtonIcon, ICON_SIZES, ICON_NAMES } from '../../../component-library'; const MAX_UNSIGNED_256_INT = new BigNumber(2).pow(256).minus(1).toString(10); @@ -57,9 +58,11 @@ export default class EditApprovalPermission extends PureComponent {
{t('editPermission')}
- hideModal()} +
diff --git a/ui/components/app/modals/new-account-modal/new-account-modal.component.js b/ui/components/app/modals/new-account-modal/new-account-modal.component.js index 18119a3f0e9e..113e08058994 100644 --- a/ui/components/app/modals/new-account-modal/new-account-modal.component.js +++ b/ui/components/app/modals/new-account-modal/new-account-modal.component.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Button from '../../../ui/button/button.component'; +import { ButtonIcon, ICON_NAMES } from '../../../component-library'; export default class NewAccountModal extends Component { static contextTypes = { @@ -43,10 +44,11 @@ export default class NewAccountModal extends Component {
{t('newAccount')} -
diff --git a/ui/components/ui/callout/callout.js b/ui/components/ui/callout/callout.js index ee9f64718c73..8f57ca010499 100644 --- a/ui/components/ui/callout/callout.js +++ b/ui/components/ui/callout/callout.js @@ -5,6 +5,7 @@ import InfoIconInverted from '../icon/info-icon-inverted.component'; import { SEVERITIES, Color } from '../../../helpers/constants/design-system'; import { MILLISECOND } from '../../../../shared/constants/time'; import Typography from '../typography'; +import { ButtonIcon, ICON_NAMES, ICON_SIZES } from '../../component-library'; export default function Callout({ severity, @@ -41,7 +42,10 @@ export default function Callout({ {children} {dismiss && ( - { setRemoved(true); }} @@ -50,9 +54,6 @@ export default function Callout({ setRemoved(true); } }} - role="button" - tabIndex={0} - className="fas fa-times callout__close-button" /> )}
diff --git a/ui/pages/add-nft/add-nft.js b/ui/pages/add-nft/add-nft.js index 4e3aa61aec7a..138ba3b9978c 100644 --- a/ui/pages/add-nft/add-nft.js +++ b/ui/pages/add-nft/add-nft.js @@ -33,6 +33,11 @@ import NftsDetectionNotice from '../../components/app/nfts-detection-notice'; import { MetaMetricsContext } from '../../contexts/metametrics'; import { AssetType } from '../../../shared/constants/transaction'; import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics'; +import { + ButtonIcon, + ICON_NAMES, + ICON_SIZES, +} from '../../components/component-library'; export default function AddNft() { const t = useI18nContext(); @@ -149,13 +154,16 @@ export default function AddNft() { {t('nftAddFailedMessage')} -
- + size={ICON_SIZES.SM} + /> ) : ( <> diff --git a/ui/pages/settings/networks-tab/custom-content-search/custom-content-search.js b/ui/pages/settings/networks-tab/custom-content-search/custom-content-search.js index 7daffb4ce4fc..8690f9e8054e 100644 --- a/ui/pages/settings/networks-tab/custom-content-search/custom-content-search.js +++ b/ui/pages/settings/networks-tab/custom-content-search/custom-content-search.js @@ -5,6 +5,7 @@ import InputAdornment from '@material-ui/core/InputAdornment'; import TextField from '../../../../components/ui/text-field'; import { I18nContext } from '../../../../contexts/i18n'; import SearchIcon from '../../../../components/ui/icon/search-icon'; +import { Icon, ICON_NAMES } from '../../../../components/component-library'; export default function CustomContentSearch({ onSearch, @@ -57,11 +58,9 @@ export default function CustomContentSearch({ position="end" onClick={() => handleSearch('')} > - )} diff --git a/ui/pages/settings/settings-search/settings-search.js b/ui/pages/settings/settings-search/settings-search.js index 45cd6c079b25..324a9579f972 100644 --- a/ui/pages/settings/settings-search/settings-search.js +++ b/ui/pages/settings/settings-search/settings-search.js @@ -9,6 +9,8 @@ import TextField from '../../../components/ui/text-field'; import { I18nContext } from '../../../contexts/i18n'; import SearchIcon from '../../../components/ui/icon/search-icon'; import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils'; +import { Icon, ICON_NAMES } from '../../../components/component-library'; +import { IconColor } from '../../../helpers/constants/design-system'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import { getSnapsRouteObjects } from '../../../selectors'; ///: END:ONLY_INCLUDE_IN @@ -83,10 +85,7 @@ export default function SettingsSearch({ onClick={() => handleSearch('')} style={{ cursor: 'pointer' }} > - + )} From eb380f92ef21a4145cdbe5b36a53339eccbd370c Mon Sep 17 00:00:00 2001 From: David Walsh Date: Mon, 27 Feb 2023 10:43:06 -0600 Subject: [PATCH 05/19] UX: Icon: Remove unwanted aria label (#17903) --- ui/components/app/account-menu/account-menu.component.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/components/app/account-menu/account-menu.component.js b/ui/components/app/account-menu/account-menu.component.js index 7e288efb3c2b..c27788402282 100644 --- a/ui/components/app/account-menu/account-menu.component.js +++ b/ui/components/app/account-menu/account-menu.component.js @@ -370,11 +370,7 @@ export default class AccountMenu extends Component { history.push(NEW_ACCOUNT_ROUTE); }} icon={ - + } text={t('createAccount')} /> From ddbd158e7995559b6d638a0e185c0eace90ed599 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Mon, 27 Feb 2023 08:48:41 -0800 Subject: [PATCH 06/19] ERC1155 Import & Dapp interaction E2E tests (#17885) --- .circleci/config.yml | 4 +- test/e2e/erc1155/import-erc1155.spec.js | 64 ++++++++++++++ test/e2e/run-all.js | 5 +- test/e2e/seeder/ganache-seeder.js | 10 +++ test/e2e/seeder/smart-contracts.js | 9 ++ test/e2e/tests/erc1155.spec.js | 109 ++++++++++++++++++++++++ 6 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 test/e2e/erc1155/import-erc1155.spec.js create mode 100644 test/e2e/tests/erc1155.spec.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 6b4a657ae69c..8fcf6367dfe7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -177,6 +177,8 @@ workflows: - test-mozilla-lint-flask - test-e2e-chrome - test-e2e-firefox + - test-e2e-chrome-nft + - test-e2e-firefox-nft - test-e2e-chrome-snaps - test-e2e-firefox-snaps - test-storybook @@ -817,7 +819,7 @@ jobs: destination: test-artifacts - store_test_results: path: test/test-results/e2e.xml - + test-e2e-firefox-snaps: executor: node-browsers parallelism: 2 diff --git a/test/e2e/erc1155/import-erc1155.spec.js b/test/e2e/erc1155/import-erc1155.spec.js new file mode 100644 index 000000000000..c58d46f2d5cc --- /dev/null +++ b/test/e2e/erc1155/import-erc1155.spec.js @@ -0,0 +1,64 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); +const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); +const FixtureBuilder = require('../fixture-builder'); + +describe('Import NFT', function () { + const smartContract = SMART_CONTRACTS.ERC1155; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + it('should be able to import an ERC1155 NFT that user owns', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + }, + async ({ driver, _, contractRegistry }) => { + const contractAddress = + contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // After login, go to NFTs tab, open the import NFT/ERC1155 form + await driver.clickElement('[data-testid="home__nfts-tab"]'); + await driver.clickElement({ text: 'Import NFTs', tag: 'a' }); + + // Enter a valid NFT that belongs to user and check success message appears + await driver.fill('[data-testid="address"]', contractAddress); + await driver.fill('[data-testid="token-id"]', '1'); + await driver.clickElement({ text: 'Add', tag: 'button' }); + + const newNftNotification = await driver.findElement({ + text: 'NFT was successfully added!', + tag: 'h6', + }); + assert.equal(await newNftNotification.isDisplayed(), true); + + // Check the imported ERC1155 and its image are displayed in the ERC1155 tab + const importedERC1155 = await driver.waitForSelector({ + css: 'h5', + text: 'Rocks', + }); + const importedERC1155Image = await driver.waitForSelector( + '[class="nfts-items__item-image"]', + ); + assert.equal(await importedERC1155.isDisplayed(), true); + assert.equal(await importedERC1155Image.isDisplayed(), true); + }, + ); + }); +}); diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index fc2fb7fad592..e65f947be466 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -72,7 +72,10 @@ async function main() { testPaths = await getTestPathsForTestDir(testDir); } else if (nft) { const testDir = path.join(__dirname, 'nft'); - testPaths = await getTestPathsForTestDir(testDir); + testPaths = [ + ...(await getTestPathsForTestDir(testDir)), + ...(await getTestPathsForTestDir(path.join(__dirname, 'erc1155'))), + ]; } else { const testDir = path.join(__dirname, 'tests'); testPaths = [ diff --git a/test/e2e/seeder/ganache-seeder.js b/test/e2e/seeder/ganache-seeder.js index 62cc1534d104..5a68134ef6ff 100644 --- a/test/e2e/seeder/ganache-seeder.js +++ b/test/e2e/seeder/ganache-seeder.js @@ -50,6 +50,16 @@ class GanacheSeeder { }); await transaction.wait(); } + + if (contractName === SMART_CONTRACTS.ERC1155) { + const transaction = await contract.mintBatch( + fromAddress, + [1, 2, 3], + [1, 1, 100000000000000], + '0x', + ); + await transaction.wait(); + } this.storeSmartContractAddress(contractName, contract.address); } diff --git a/test/e2e/seeder/smart-contracts.js b/test/e2e/seeder/smart-contracts.js index 247c003504ce..fe0f0262a0a6 100644 --- a/test/e2e/seeder/smart-contracts.js +++ b/test/e2e/seeder/smart-contracts.js @@ -5,6 +5,8 @@ const { piggybankAbi, collectiblesAbi, collectiblesBytecode, + erc1155Abi, + erc1155Bytecode, failingContractAbi, failingContractBytecode, multisigAbi, @@ -25,6 +27,11 @@ const nftsFactory = { abi: collectiblesAbi, }; +const erc1155Factory = { + bytecode: erc1155Bytecode, + abi: erc1155Abi, +}; + const piggybankFactory = { bytecode: piggybankBytecode, abi: piggybankAbi, @@ -43,6 +50,7 @@ const multisigFactory = { const SMART_CONTRACTS = { HST: 'hst', NFTS: 'nfts', + ERC1155: 'erc1155', PIGGYBANK: 'piggybank', FAILING: 'failing', MULTISIG: 'multisig', @@ -51,6 +59,7 @@ const SMART_CONTRACTS = { const contractConfiguration = { [SMART_CONTRACTS.HST]: hstFactory, [SMART_CONTRACTS.NFTS]: nftsFactory, + [SMART_CONTRACTS.ERC1155]: erc1155Factory, [SMART_CONTRACTS.PIGGYBANK]: piggybankFactory, [SMART_CONTRACTS.FAILING]: failingContract, [SMART_CONTRACTS.MULTISIG]: multisigFactory, diff --git a/test/e2e/tests/erc1155.spec.js b/test/e2e/tests/erc1155.spec.js new file mode 100644 index 000000000000..7f051399033c --- /dev/null +++ b/test/e2e/tests/erc1155.spec.js @@ -0,0 +1,109 @@ +const { convertToHexValue, withFixtures } = require('../helpers'); +const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); +const FixtureBuilder = require('../fixture-builder'); + +describe('ERC1155', function () { + const smartContract = SMART_CONTRACTS.ERC1155; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + it('should mint', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await driver.openNewPage(`http://127.0.0.1:8080/?contract=${contract}`); + await driver.findClickableElement('#deployButton'); + + // Mint + await driver.fill('#batchMintTokenIds', '1, 2, 3'); + await driver.fill('#batchMintIdAmounts', '1, 1, 1000000000000000'); + await driver.clickElement('#batchMintButton'); + + // Notification + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Confirm Mint + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + { timeout: 10000 }, + ); + }, + ); + }); + + it('should batch transfers', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.openNewPage(`http://127.0.0.1:8080/?contract=${contract}`); + + await driver.fill('#batchTransferTokenIds', '1, 2, 3'); + await driver.fill('#batchTransferTokenAmounts', '1, 1, 1000000000000'); + await driver.clickElement('#batchTransferFromButton'); + + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + { timeout: 10000 }, + ); + }, + ); + }); +}); From e223348fb3497ba16eb804c9e427f057b3acab84 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Mon, 27 Feb 2023 13:19:08 -0330 Subject: [PATCH 07/19] Update `eth-json-rpc-middleware` from v9 to v10 (#17591) This release only includes one breaking change, which is the renaming of the package to be under the `@metamask` scope. It includes improvements to the types that will unblock migrating our network clients to TypeScript. --- .../controllers/network/createInfuraClient.js | 2 +- .../network/createJsonRpcClient.js | 2 +- .../controllers/network/network-controller.js | 2 +- .../network/network-controller.test.js | 6 +- .../network/provider-api-tests/helpers.js | 2 +- app/scripts/lib/createMetamaskMiddleware.js | 2 +- app/scripts/metamask-controller.js | 2 +- lavamoat/browserify/beta/policy.json | 116 +++++++++--------- lavamoat/browserify/desktop/policy.json | 116 +++++++++--------- lavamoat/browserify/flask/policy.json | 116 +++++++++--------- lavamoat/browserify/main/policy.json | 116 +++++++++--------- package.json | 2 +- test/stub/provider.js | 2 +- yarn.lock | 40 +++--- 14 files changed, 263 insertions(+), 263 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 111e742ce68a..76461eb6226e 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -6,7 +6,7 @@ import { createInflightCacheMiddleware, createBlockTrackerInspectorMiddleware, providerFromMiddleware, -} from 'eth-json-rpc-middleware'; +} from '@metamask/eth-json-rpc-middleware'; import { createInfuraMiddleware } from '@metamask/eth-json-rpc-infura'; import { PollingBlockTracker } from 'eth-block-tracker'; diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index bd5f648d3231..b8cf0e7aaeb0 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -6,7 +6,7 @@ import { createInflightCacheMiddleware, createBlockTrackerInspectorMiddleware, providerFromMiddleware, -} from 'eth-json-rpc-middleware'; +} from '@metamask/eth-json-rpc-middleware'; import { PollingBlockTracker } from 'eth-block-tracker'; import { SECOND } from '../../../../shared/constants/time'; diff --git a/app/scripts/controllers/network/network-controller.js b/app/scripts/controllers/network/network-controller.js index 2595ae99da03..5c4d3d456f21 100644 --- a/app/scripts/controllers/network/network-controller.js +++ b/app/scripts/controllers/network/network-controller.js @@ -5,7 +5,7 @@ import { JsonRpcEngine } from 'json-rpc-engine'; import { providerFromEngine, providerFromMiddleware, -} from 'eth-json-rpc-middleware'; +} from '@metamask/eth-json-rpc-middleware'; import log from 'loglevel'; import { createSwappableProxy, diff --git a/app/scripts/controllers/network/network-controller.test.js b/app/scripts/controllers/network/network-controller.test.js index 939d9aa07124..df2a76dbd925 100644 --- a/app/scripts/controllers/network/network-controller.test.js +++ b/app/scripts/controllers/network/network-controller.test.js @@ -2,13 +2,13 @@ import { inspect, isDeepStrictEqual, promisify } from 'util'; import { isMatch } from 'lodash'; import nock from 'nock'; import sinon from 'sinon'; -import * as ethJsonRpcMiddlewareModule from 'eth-json-rpc-middleware'; +import * as ethJsonRpcMiddlewareModule from '@metamask/eth-json-rpc-middleware'; import NetworkController from './network-controller'; -jest.mock('eth-json-rpc-middleware', () => { +jest.mock('@metamask/eth-json-rpc-middleware', () => { return { __esModule: true, - ...jest.requireActual('eth-json-rpc-middleware'), + ...jest.requireActual('@metamask/eth-json-rpc-middleware'), }; }); diff --git a/app/scripts/controllers/network/provider-api-tests/helpers.js b/app/scripts/controllers/network/provider-api-tests/helpers.js index 38bfe0d87952..f8deb72f85d4 100644 --- a/app/scripts/controllers/network/provider-api-tests/helpers.js +++ b/app/scripts/controllers/network/provider-api-tests/helpers.js @@ -1,7 +1,7 @@ import nock from 'nock'; import sinon from 'sinon'; import { JsonRpcEngine } from 'json-rpc-engine'; -import { providerFromEngine } from 'eth-json-rpc-middleware'; +import { providerFromEngine } from '@metamask/eth-json-rpc-middleware'; import EthQuery from 'eth-query'; import createInfuraClient from '../createInfuraClient'; import createJsonRpcClient from '../createJsonRpcClient'; diff --git a/app/scripts/lib/createMetamaskMiddleware.js b/app/scripts/lib/createMetamaskMiddleware.js index cee6b9b95e2c..c0114dd2323c 100644 --- a/app/scripts/lib/createMetamaskMiddleware.js +++ b/app/scripts/lib/createMetamaskMiddleware.js @@ -1,5 +1,5 @@ import { createScaffoldMiddleware, mergeMiddleware } from 'json-rpc-engine'; -import { createWalletMiddleware } from 'eth-json-rpc-middleware'; +import { createWalletMiddleware } from '@metamask/eth-json-rpc-middleware'; import { createPendingNonceMiddleware, createPendingTxMiddleware, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 73578b8348c4..2c3231c901a1 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -5,7 +5,7 @@ import { storeAsStream } from '@metamask/obs-store/dist/asStream'; import { JsonRpcEngine } from 'json-rpc-engine'; import { debounce } from 'lodash'; import { createEngineStream } from 'json-rpc-middleware-stream'; -import { providerAsMiddleware } from 'eth-json-rpc-middleware'; +import { providerAsMiddleware } from '@metamask/eth-json-rpc-middleware'; import { KeyringController, keyringBuilderFactory, diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 4da2914dc318..2d824d949339 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -871,14 +871,34 @@ "ethjs>ethjs-util>strip-hex-prefix": true } }, + "@metamask/eth-json-rpc-middleware": { + "globals": { + "URL": true, + "btoa": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/eth-json-rpc-middleware>pify": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/utils": true, + "browserify>browser-resolve": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "json-rpc-engine>@metamask/safe-event-emitter": true, + "lavamoat>json-stable-stringify": true, + "vinyl>clone": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/eth-keyring-controller>obs-store": true, "@metamask/rpc-methods>@metamask/browser-passworder": true, - "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true + "browserify>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -887,9 +907,9 @@ }, "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true } }, @@ -909,12 +929,45 @@ "crypto": true } }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, + "bn.js": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true, "ethereumjs-wallet>randombytes": true } @@ -2575,59 +2628,6 @@ "wait-on>rxjs>tslib": true } }, - "eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/utils": true, - "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, - "eth-json-rpc-middleware>pify": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "json-rpc-engine>@metamask/safe-event-emitter": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, - "eth-lattice-keyring>@ethereumjs/util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "eth-keyring-controller>@metamask/browser-passworder": { "globals": { "crypto": true @@ -3022,8 +3022,8 @@ }, "packages": { "@babel/runtime": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-trezor-keyring>trezor-connect>cross-fetch": true } }, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 79309f375970..e3b4c0d4de71 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -923,14 +923,34 @@ "ethjs>ethjs-util>strip-hex-prefix": true } }, + "@metamask/eth-json-rpc-middleware": { + "globals": { + "URL": true, + "btoa": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/eth-json-rpc-middleware>pify": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/utils": true, + "browserify>browser-resolve": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "json-rpc-engine>@metamask/safe-event-emitter": true, + "lavamoat>json-stable-stringify": true, + "vinyl>clone": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/eth-keyring-controller>obs-store": true, "@metamask/rpc-methods>@metamask/browser-passworder": true, - "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true + "browserify>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -939,9 +959,9 @@ }, "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true } }, @@ -961,12 +981,45 @@ "crypto": true } }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, + "bn.js": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true, "ethereumjs-wallet>randombytes": true } @@ -2941,59 +2994,6 @@ "wait-on>rxjs>tslib": true } }, - "eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/utils": true, - "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, - "eth-json-rpc-middleware>pify": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "json-rpc-engine>@metamask/safe-event-emitter": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, - "eth-lattice-keyring>@ethereumjs/util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "eth-keyring-controller>@metamask/browser-passworder": { "globals": { "crypto": true @@ -3388,8 +3388,8 @@ }, "packages": { "@babel/runtime": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-trezor-keyring>trezor-connect>cross-fetch": true } }, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 1695b495fc66..9b6ec427f0a3 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -871,14 +871,34 @@ "ethjs>ethjs-util>strip-hex-prefix": true } }, + "@metamask/eth-json-rpc-middleware": { + "globals": { + "URL": true, + "btoa": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/eth-json-rpc-middleware>pify": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/utils": true, + "browserify>browser-resolve": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "json-rpc-engine>@metamask/safe-event-emitter": true, + "lavamoat>json-stable-stringify": true, + "vinyl>clone": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/eth-keyring-controller>obs-store": true, "@metamask/rpc-methods>@metamask/browser-passworder": true, - "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true + "browserify>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -887,9 +907,9 @@ }, "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true } }, @@ -909,12 +929,45 @@ "crypto": true } }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, + "bn.js": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true, "ethereumjs-wallet>randombytes": true } @@ -2889,59 +2942,6 @@ "wait-on>rxjs>tslib": true } }, - "eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/utils": true, - "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, - "eth-json-rpc-middleware>pify": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "json-rpc-engine>@metamask/safe-event-emitter": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, - "eth-lattice-keyring>@ethereumjs/util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "eth-keyring-controller>@metamask/browser-passworder": { "globals": { "crypto": true @@ -3336,8 +3336,8 @@ }, "packages": { "@babel/runtime": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-trezor-keyring>trezor-connect>cross-fetch": true } }, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 4da2914dc318..2d824d949339 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -871,14 +871,34 @@ "ethjs>ethjs-util>strip-hex-prefix": true } }, + "@metamask/eth-json-rpc-middleware": { + "globals": { + "URL": true, + "btoa": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/eth-json-rpc-middleware>pify": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/utils": true, + "browserify>browser-resolve": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "json-rpc-engine>@metamask/safe-event-emitter": true, + "lavamoat>json-stable-stringify": true, + "vinyl>clone": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/eth-keyring-controller>obs-store": true, "@metamask/rpc-methods>@metamask/browser-passworder": true, - "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true + "browserify>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -887,9 +907,9 @@ }, "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true } }, @@ -909,12 +929,45 @@ "crypto": true } }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, + "bn.js": true, + "browserify>buffer": true, + "eth-lattice-keyring>@ethereumjs/util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-lattice-keyring>@ethereumjs/util": true, "ethereumjs-wallet>randombytes": true } @@ -2575,59 +2628,6 @@ "wait-on>rxjs>tslib": true } }, - "eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/utils": true, - "browserify>browser-resolve": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, - "eth-json-rpc-middleware>pify": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "json-rpc-engine>@metamask/safe-event-emitter": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": true, - "eth-lattice-keyring>@ethereumjs/util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "eth-json-rpc-middleware>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "eth-keyring-controller>@metamask/browser-passworder": { "globals": { "crypto": true @@ -3022,8 +3022,8 @@ }, "packages": { "@babel/runtime": true, + "@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, "browserify>events": true, - "eth-json-rpc-middleware>@metamask/eth-sig-util": true, "eth-trezor-keyring>trezor-connect>cross-fetch": true } }, diff --git a/package.json b/package.json index 2639e49c91f1..426f51e11049 100644 --- a/package.json +++ b/package.json @@ -233,6 +233,7 @@ "@metamask/design-tokens": "^1.9.0", "@metamask/desktop": "^0.2.0", "@metamask/eth-json-rpc-infura": "^7.0.0", + "@metamask/eth-json-rpc-middleware": "^10.0.0", "@metamask/eth-keyring-controller": "^10.0.0", "@metamask/eth-ledger-bridge-keyring": "^0.13.0", "@metamask/eth-token-tracker": "^4.0.0", @@ -286,7 +287,6 @@ "eth-block-tracker": "^6.0.0", "eth-ens-namehash": "^2.0.8", "eth-json-rpc-filters": "^6.0.0", - "eth-json-rpc-middleware": "^9.0.1", "eth-lattice-keyring": "^0.12.3", "eth-method-registry": "^2.0.0", "eth-query": "^2.1.2", diff --git a/test/stub/provider.js b/test/stub/provider.js index 055c02a78be4..e070d55fa6b0 100644 --- a/test/stub/provider.js +++ b/test/stub/provider.js @@ -1,5 +1,5 @@ import { JsonRpcEngine, createScaffoldMiddleware } from 'json-rpc-engine'; -import { providerAsMiddleware } from 'eth-json-rpc-middleware'; +import { providerAsMiddleware } from '@metamask/eth-json-rpc-middleware'; import Ganache from 'ganache'; export function getTestSeed() { diff --git a/yarn.lock b/yarn.lock index cc9027552cd1..ffb694e88c7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3769,6 +3769,25 @@ __metadata: languageName: node linkType: hard +"@metamask/eth-json-rpc-middleware@npm:^10.0.0": + version: 10.0.0 + resolution: "@metamask/eth-json-rpc-middleware@npm:10.0.0" + dependencies: + "@metamask/eth-sig-util": ^5.0.0 + "@metamask/safe-event-emitter": ^2.0.0 + "@metamask/utils": ^3.0.3 + btoa: ^1.2.1 + clone: ^2.1.1 + eth-block-tracker: ^5.0.1 + eth-rpc-errors: ^4.0.3 + json-rpc-engine: ^6.1.0 + json-stable-stringify: ^1.0.1 + node-fetch: ^2.6.7 + pify: ^3.0.0 + checksum: c754b3a39f175698070b4d07076e692d3080738bd25157c3b93114d286c975ee6895d5793b4188ca3d0abbcdef04bfde9e2d4835251a6b725b002d3750bf98de + languageName: node + linkType: hard + "@metamask/eth-keyring-controller@npm:^10.0.0": version: 10.0.0 resolution: "@metamask/eth-keyring-controller@npm:10.0.0" @@ -15426,25 +15445,6 @@ __metadata: languageName: node linkType: hard -"eth-json-rpc-middleware@npm:^9.0.1": - version: 9.0.1 - resolution: "eth-json-rpc-middleware@npm:9.0.1" - dependencies: - "@metamask/eth-sig-util": ^5.0.0 - "@metamask/safe-event-emitter": ^2.0.0 - "@metamask/utils": ^3.0.3 - btoa: ^1.2.1 - clone: ^2.1.1 - eth-block-tracker: ^5.0.1 - eth-rpc-errors: ^4.0.3 - json-rpc-engine: ^6.1.0 - json-stable-stringify: ^1.0.1 - node-fetch: ^2.6.7 - pify: ^3.0.0 - checksum: 9512829a6958df6ef739b891a0c0804b51a140407fd2e3ddaaa6b18d975796646cfcf7f7305a18beb7903db09e0c7a91b06dc5434b6bd2d6cdb85d992d9fd3ab - languageName: node - linkType: hard - "eth-lattice-keyring@npm:^0.12.3": version: 0.12.3 resolution: "eth-lattice-keyring@npm:0.12.3" @@ -24034,6 +24034,7 @@ __metadata: "@metamask/eslint-config-nodejs": ^9.0.0 "@metamask/eslint-config-typescript": ^9.0.1 "@metamask/eth-json-rpc-infura": ^7.0.0 + "@metamask/eth-json-rpc-middleware": ^10.0.0 "@metamask/eth-keyring-controller": ^10.0.0 "@metamask/eth-ledger-bridge-keyring": ^0.13.0 "@metamask/eth-token-tracker": ^4.0.0 @@ -24166,7 +24167,6 @@ __metadata: eth-block-tracker: ^6.0.0 eth-ens-namehash: ^2.0.8 eth-json-rpc-filters: ^6.0.0 - eth-json-rpc-middleware: ^9.0.1 eth-lattice-keyring: ^0.12.3 eth-method-registry: ^2.0.0 eth-query: ^2.1.2 From cb113dd2a65d9a650c25fb6cb56e371dd07b2ae5 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Mon, 27 Feb 2023 15:16:22 -0330 Subject: [PATCH 08/19] Convert the migration template to TypeScript (#17836) The migration template has been converted to TypeScript. We can start writing migrations in TypeScript today; they have no dependencies on JavaScript modules. --- app/scripts/migrations/template.js | 29 ------------------------- app/scripts/migrations/template.test.js | 8 +++---- app/scripts/migrations/template.ts | 28 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 app/scripts/migrations/template.js create mode 100644 app/scripts/migrations/template.ts diff --git a/app/scripts/migrations/template.js b/app/scripts/migrations/template.js deleted file mode 100644 index b3f050dfcd76..000000000000 --- a/app/scripts/migrations/template.js +++ /dev/null @@ -1,29 +0,0 @@ -// next version number -/* - -description of migration and what it does - -*/ - -import { cloneDeep } from 'lodash'; - -const version = 0; - -export default { - version, - - async migrate(originalVersionedData) { - const versionedData = cloneDeep(originalVersionedData); - versionedData.meta.version = version; - const state = versionedData.data; - const newState = transformState(state); - versionedData.data = newState; - return versionedData; - }, -}; - -function transformState(state) { - const newState = state; - // transform state here - return newState; -} diff --git a/app/scripts/migrations/template.test.js b/app/scripts/migrations/template.test.js index f24dc1bca6eb..2c0e0bcc9e89 100644 --- a/app/scripts/migrations/template.test.js +++ b/app/scripts/migrations/template.test.js @@ -1,13 +1,13 @@ -import migrationTemplate from './template'; +import { migrate, version } from './template'; const storage = { - meta: {}, + meta: { version: -1 }, data: {}, }; describe('storage is migrated successfully', () => { it('should work', async () => { - const migratedData = await migrationTemplate.migrate(storage); - expect(migratedData.meta.version).toStrictEqual(0); + const migratedData = await migrate(storage); + expect(migratedData.meta.version).toStrictEqual(version); }); }); diff --git a/app/scripts/migrations/template.ts b/app/scripts/migrations/template.ts new file mode 100644 index 000000000000..e9c70cd47bec --- /dev/null +++ b/app/scripts/migrations/template.ts @@ -0,0 +1,28 @@ +import { cloneDeep } from 'lodash'; + +export const version = 0; + +/** + * Explain the purpose of the migration here. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate(originalVersionedData: { + meta: { version: number }; + data: Record; +}) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + versionedData.data = transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + const newState = state; + // transform state here + return newState; +} From 878bb4ab25d241804bee8c41adb31d9597cbc1a8 Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Tue, 28 Feb 2023 12:55:58 +0530 Subject: [PATCH 09/19] Ux: Icon: Update fa-eye with ICON_NAMES.EYE (#17800) * updated fa-eye * Fix build error * resolved lint error * lint error fix --------- Co-authored-by: David Walsh --- ui/helpers/utils/permission.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ui/helpers/utils/permission.js b/ui/helpers/utils/permission.js index de60aaf5719b..b625c414d610 100644 --- a/ui/helpers/utils/permission.js +++ b/ui/helpers/utils/permission.js @@ -1,6 +1,7 @@ import deepFreeze from 'deep-freeze-strict'; -///: BEGIN:ONLY_INCLUDE_IN(flask) import React from 'react'; + +///: BEGIN:ONLY_INCLUDE_IN(flask) import { getRpcCaveatOrigins } from '@metamask/snaps-controllers/dist/snaps/endowments/rpc'; import { SnapCaveatType } from '@metamask/snaps-utils'; import { isNonEmptyArray } from '@metamask/controller-utils'; @@ -14,16 +15,19 @@ import { } from '../../../shared/constants/permissions'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import { SNAPS_METADATA } from '../../../shared/constants/snaps'; -import { Icon, ICON_NAMES } from '../../components/component-library'; -import { coinTypeToProtocolName, getSnapDerivationPathName } from './util'; ///: END:ONLY_INCLUDE_IN +import { Icon, ICON_NAMES } from '../../components/component-library'; +import { Color } from '../constants/design-system'; +import { coinTypeToProtocolName, getSnapDerivationPathName } from './util'; // eslint-disable-line no-unused-vars const UNKNOWN_PERMISSION = Symbol('unknown'); const PERMISSION_DESCRIPTIONS = deepFreeze({ [RestrictedMethods.eth_accounts]: (t) => ({ label: t('permission_ethereumAccounts'), - leftIcon: 'fas fa-eye', + leftIcon: ( + + ), rightIcon: null, weight: 2, }), @@ -49,7 +53,13 @@ const PERMISSION_DESCRIPTIONS = deepFreeze({ [RestrictedMethods.snap_getBip32PublicKey]: (t, _, permissionValue) => permissionValue.caveats[0].value.map(({ path, curve }) => { const baseDescription = { - leftIcon: 'fas fa-eye', + leftIcon: ( + + ), rightIcon: null, weight: 1, }; From 3678894df29914e182a4bdd8517607112373d63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Tavares?= Date: Tue, 28 Feb 2023 08:31:20 +0000 Subject: [PATCH 10/19] chore: bump desktop common package to 0.3.0 (#17912) --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 426f51e11049..89eaab77d744 100644 --- a/package.json +++ b/package.json @@ -231,7 +231,7 @@ "@metamask/contract-metadata": "^2.2.0", "@metamask/controller-utils": "^1.0.0", "@metamask/design-tokens": "^1.9.0", - "@metamask/desktop": "^0.2.0", + "@metamask/desktop": "^0.3.0", "@metamask/eth-json-rpc-infura": "^7.0.0", "@metamask/eth-json-rpc-middleware": "^10.0.0", "@metamask/eth-keyring-controller": "^10.0.0", diff --git a/yarn.lock b/yarn.lock index ffb694e88c7e..23cc3f19cfd2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3666,9 +3666,9 @@ __metadata: languageName: node linkType: hard -"@metamask/desktop@npm:^0.2.0": - version: 0.2.0 - resolution: "@metamask/desktop@npm:0.2.0" +"@metamask/desktop@npm:^0.3.0": + version: 0.3.0 + resolution: "@metamask/desktop@npm:0.3.0" dependencies: "@metamask/obs-store": ^5.0.0 eciesjs: ^0.3.15 @@ -3680,7 +3680,7 @@ __metadata: uuid: ^8.3.2 webextension-polyfill: ^0.8.0 ws: ^7.4.6 - checksum: 052d5dd58951c77733b538d9c392a5aa5b7d87bb600cf04a97e3213048f84936a4446adbf901258417c8eed01dbc68eb2c7117a53b6af7a416ecea975460ffb7 + checksum: fb0c0582feb326f01ffe98e26dec8e62861aea7fe6fb0ce44e78b81ca95ec37b6b2c12398e3b3d2b5ff6253ff227c17683a72cea3b1532c088c27c8ebaea2c4e languageName: node linkType: hard @@ -24027,7 +24027,7 @@ __metadata: "@metamask/contract-metadata": ^2.2.0 "@metamask/controller-utils": ^1.0.0 "@metamask/design-tokens": ^1.9.0 - "@metamask/desktop": ^0.2.0 + "@metamask/desktop": ^0.3.0 "@metamask/eslint-config": ^9.0.0 "@metamask/eslint-config-jest": ^9.0.0 "@metamask/eslint-config-mocha": ^9.0.0 From afed985b4806493326bba9bd136715aaeb8b6ee1 Mon Sep 17 00:00:00 2001 From: weizman Date: Tue, 28 Feb 2023 13:29:24 +0200 Subject: [PATCH 11/19] Turn off LM scuttling feature for dev builds (#17771) --- development/build/index.js | 10 +++++++++- development/build/utils.js | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/development/build/index.js b/development/build/index.js index 3e8faa3721cd..456128c1fa49 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -73,9 +73,17 @@ async function defineAndRunBuildTasks() { version, } = await parseArgv(); + // scuttle on production/tests environment only + const shouldScuttle = ['dist', 'prod', 'test'].includes(entryTask); + + console.log( + `Building lavamoat runtime file`, + `(scuttling is ${shouldScuttle ? 'on' : 'off'})`, + ); + // build lavamoat runtime file await lavapack.buildRuntime({ - scuttleGlobalThis: true, + scuttleGlobalThis: applyLavaMoat && shouldScuttle, scuttleGlobalThisExceptions: [ // globals used by different mm deps outside of lm compartment 'toString', diff --git a/development/build/utils.js b/development/build/utils.js index fde7afbbd92a..e003f7c27f9c 100644 --- a/development/build/utils.js +++ b/development/build/utils.js @@ -163,7 +163,7 @@ function wrapAgainstScuttling(content, bag = {}) { const proxy = new Proxy(bag, { set: function set(target, prop, value) { if (bag.hasOwnProperty(prop) || prop.startsWith('on')) { - return bag[prop] = global[prop] = value; + return (bag[prop] = global[prop] = value) || true; } }, }); From e015e027b65323368ede555d0bb2bb22057e1787 Mon Sep 17 00:00:00 2001 From: Bowen Sanders Date: Tue, 28 Feb 2023 05:07:00 -0800 Subject: [PATCH 12/19] [FLASK] Create E2E test for cronjobs (#17365) * added long test * Wait for a maximum of 65 seconds, not a hardcoded length * Fix lint --------- Co-authored-by: Frederik Bolding --- test/e2e/snaps/test-snap-cronjob.spec.js | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 test/e2e/snaps/test-snap-cronjob.spec.js diff --git a/test/e2e/snaps/test-snap-cronjob.spec.js b/test/e2e/snaps/test-snap-cronjob.spec.js new file mode 100644 index 000000000000..ae9944c17bfc --- /dev/null +++ b/test/e2e/snaps/test-snap-cronjob.spec.js @@ -0,0 +1,99 @@ +const { strict: assert } = require('assert'); +const { withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +describe('Test Snap Cronjob', function () { + it('can trigger a cronjob to open a dialog every minute', async function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: 25000000000000000000, + }, + ], + }; + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + // enter pw into extension + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // navigate to test snaps page and connect + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + await driver.delay(1000); + const snapButton = await driver.findElement('#connectCronjobSnap'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectCronjobSnap'); + await driver.delay(1000); + + // switch to metamask extension and click connect + let windowHandles = await driver.waitUntilXWindowHandles( + 3, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.clickElement( + { + text: 'Connect', + tag: 'button', + }, + 10000, + ); + + await driver.delay(2000); + + // approve install of snap + windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.clickElement({ + text: 'Approve & install', + tag: 'button', + }); + + // delay for npm installation + await driver.delay(2000); + + // click send inputs on test snap page + windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // switch to dialog popup, wait for a maximum of 65 seconds + windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 65000); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.delay(1000); + + // look for the dialog popup to verify cronjob fired + const error = await driver.findElement('.snap-delineator__content'); + const text = await error.getText(); + assert.equal(text.includes(`Cronjob\nfired`), true); + + // try to click on the Ok button and pass test if it works + await driver.clickElement({ + text: 'Ok', + tag: 'button', + }); + }, + ); + }); +}); From 5419f9414c99b5a37ca1190cef0727b78480c3b0 Mon Sep 17 00:00:00 2001 From: chloeYue <105063779+chloeYue@users.noreply.github.com> Date: Tue, 28 Feb 2023 15:23:06 +0100 Subject: [PATCH 13/19] Add unhappypath test case for importing ERC1155 (#17923) * add unhappypath test case for importing ERC1155 token --- .../{erc1155 => nft}/import-erc1155.spec.js | 39 ++++++++++++++++++- test/e2e/run-all.js | 5 +-- 2 files changed, 39 insertions(+), 5 deletions(-) rename test/e2e/{erc1155 => nft}/import-erc1155.spec.js (60%) diff --git a/test/e2e/erc1155/import-erc1155.spec.js b/test/e2e/nft/import-erc1155.spec.js similarity index 60% rename from test/e2e/erc1155/import-erc1155.spec.js rename to test/e2e/nft/import-erc1155.spec.js index c58d46f2d5cc..e74f6b224fc9 100644 --- a/test/e2e/erc1155/import-erc1155.spec.js +++ b/test/e2e/nft/import-erc1155.spec.js @@ -3,7 +3,7 @@ const { convertToHexValue, withFixtures } = require('../helpers'); const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); const FixtureBuilder = require('../fixture-builder'); -describe('Import NFT', function () { +describe('Import ERC1155 NFT', function () { const smartContract = SMART_CONTRACTS.ERC1155; const ganacheOptions = { accounts: [ @@ -61,4 +61,41 @@ describe('Import NFT', function () { }, ); }); + + it('should not be able to import an ERC1155 NFT that does not belong to user', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + }, + async ({ driver, _, contractRegistry }) => { + const contractAddress = + contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // After login, go to NFTs tab, open the import NFT form + await driver.clickElement('[data-testid="home__nfts-tab"]'); + await driver.clickElement({ text: 'Import NFTs', tag: 'a' }); + + // Enter an NFT that not belongs to user with a valid address and an invalid token id + await driver.fill('[data-testid="address"]', contractAddress); + await driver.fill('[data-testid="token-id"]', '4'); + await driver.clickElement({ text: 'Add', tag: 'button' }); + + // Check error message appears + const invalidNftNotification = await driver.findElement({ + text: 'NFT can’t be added as the ownership details do not match. Make sure you have entered correct information.', + tag: 'h6', + }); + assert.equal(await invalidNftNotification.isDisplayed(), true); + }, + ); + }); }); diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index e65f947be466..fc2fb7fad592 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -72,10 +72,7 @@ async function main() { testPaths = await getTestPathsForTestDir(testDir); } else if (nft) { const testDir = path.join(__dirname, 'nft'); - testPaths = [ - ...(await getTestPathsForTestDir(testDir)), - ...(await getTestPathsForTestDir(path.join(__dirname, 'erc1155'))), - ]; + testPaths = await getTestPathsForTestDir(testDir); } else { const testDir = path.join(__dirname, 'tests'); testPaths = [ From 426e3c37a42e5916ae7354bd01a0ac4ba217dd7f Mon Sep 17 00:00:00 2001 From: Filip Sekulic Date: Tue, 28 Feb 2023 15:23:24 +0100 Subject: [PATCH 14/19] Fixed accounts auto scrolling (#17075) * Fixed a bug * Fixed additional bug --- ui/components/ui/account-list/account-list.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/components/ui/account-list/account-list.js b/ui/components/ui/account-list/account-list.js index a005857ae92f..2cfdf70d2aae 100644 --- a/ui/components/ui/account-list/account-list.js +++ b/ui/components/ui/account-list/account-list.js @@ -1,6 +1,7 @@ -import React, { useLayoutEffect, useRef } from 'react'; +import React, { memo, useLayoutEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; +import { isEqual } from 'lodash'; import { useI18nContext } from '../../../hooks/useI18nContext'; import CheckBox, { CHECKED, INDETERMINATE, UNCHECKED } from '../check-box'; import Identicon from '../identicon'; @@ -23,7 +24,7 @@ const AccountList = ({ const selectedAccountScrollRef = useRef(null); useLayoutEffect(() => { selectedAccountScrollRef.current?.scrollIntoView({ behavior: 'smooth' }); - }, []); + }, [selectedAccounts]); const Header = () => { let checked; @@ -178,4 +179,6 @@ AccountList.propTypes = { handleAccountClick: PropTypes.func.isRequired, }; -export default AccountList; +export default memo(AccountList, (prevProps, nextProps) => { + return isEqual(prevProps.selectedAccounts, nextProps.selectedAccounts); +}); From 9e7bc210a2d5af28c41812a2a98b7dd5fecbe32a Mon Sep 17 00:00:00 2001 From: chloeYue <105063779+chloeYue@users.noreply.github.com> Date: Tue, 28 Feb 2023 15:25:18 +0100 Subject: [PATCH 15/19] Add e2e test remove erc1155 token (#17925) * add e2e test remove erc1155 token --- test/e2e/nft/remove-erc1155.spec.js | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 test/e2e/nft/remove-erc1155.spec.js diff --git a/test/e2e/nft/remove-erc1155.spec.js b/test/e2e/nft/remove-erc1155.spec.js new file mode 100644 index 000000000000..9ad21b6c5972 --- /dev/null +++ b/test/e2e/nft/remove-erc1155.spec.js @@ -0,0 +1,63 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); +const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); +const FixtureBuilder = require('../fixture-builder'); + +describe('Remove ERC1155 NFT', function () { + const smartContract = SMART_CONTRACTS.ERC1155; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + it('user should be able to remove ERC1155 NFT on details page', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + ganacheOptions, + smartContract, + title: this.test.title, + }, + async ({ driver, _, contractRegistry }) => { + const contractAddress = + contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // After login, go to NFTs tab and import an ERC1155 NFT + await driver.clickElement('[data-testid="home__nfts-tab"]'); + await driver.clickElement({ text: 'Import NFTs', tag: 'a' }); + + await driver.fill('[data-testid="address"]', contractAddress); + await driver.fill('[data-testid="token-id"]', '1'); + await driver.clickElement({ text: 'Add', tag: 'button' }); + + // Open the details and click remove nft button + await driver.clickElement('.nfts-items__item-image'); + await driver.clickElement('[data-testid="nft-options__button"]'); + await driver.clickElement('[data-testid="nft-item-remove"]'); + + // Check the remove NFT toaster is displayed + const removeNftNotification = await driver.findElement({ + text: 'NFT was successfully removed!', + tag: 'h6', + }); + assert.equal(await removeNftNotification.isDisplayed(), true); + + // Check the imported ERC1155 NFT disappeared in the NFT tab + const noNftInfo = await driver.waitForSelector({ + css: 'h4', + text: 'No NFTs yet', + }); + assert.equal(await noNftInfo.isDisplayed(), true); + }, + ); + }); +}); From 656b6d1963fe856adaf52c7db41d762d650f409f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Tavares?= Date: Tue, 28 Feb 2023 14:51:43 +0000 Subject: [PATCH 16/19] fix: desktop lavamoat policies (#17928) --- lavamoat/browserify/desktop/policy.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index e3b4c0d4de71..17e096890659 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -816,6 +816,8 @@ }, "@metamask/desktop": { "globals": { + "TextDecoder": true, + "TextEncoder": true, "WebSocket": true, "clearInterval": true, "clearTimeout": true, From 90ae4980b3aca3f2610a24ade06cf7e6db928209 Mon Sep 17 00:00:00 2001 From: Erik Marks <25517051+rekmarks@users.noreply.github.com> Date: Tue, 28 Feb 2023 10:21:33 -0800 Subject: [PATCH 17/19] Update snaps locale messages for casing and content (#17915) * Update snaps locale messages for casing and content * Fix non-English locales * udpate e2e test --------- Co-authored-by: Guillaume Roux --- app/_locales/de/messages.json | 4 ++-- app/_locales/el/messages.json | 4 ++-- app/_locales/en/messages.json | 18 +++++++++--------- app/_locales/es/messages.json | 4 ++-- app/_locales/es_419/messages.json | 2 +- app/_locales/fr/messages.json | 4 ++-- app/_locales/hi/messages.json | 4 ++-- app/_locales/id/messages.json | 4 ++-- app/_locales/ja/messages.json | 4 ++-- app/_locales/ko/messages.json | 4 ++-- app/_locales/pt/messages.json | 4 ++-- app/_locales/pt_BR/messages.json | 2 +- app/_locales/ru/messages.json | 4 ++-- app/_locales/tl/messages.json | 4 ++-- app/_locales/tr/messages.json | 4 ++-- app/_locales/vi/messages.json | 4 ++-- app/_locales/zh_CN/messages.json | 4 ++-- test/e2e/snaps/test-snap-management.spec.js | 2 +- 18 files changed, 40 insertions(+), 40 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 2c4eb3e1e1eb..e44c433ec81a 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Details ansehen", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Hinzugefügt am", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Verbinden Sie sich mit dem $1-Snap.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Regelmäßige Transaktionen planen und ausführen.", diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 021bca9e295a..1fc07474ba00 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Προβολή λεπτομερειών", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Προστέθηκε στις", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Συνδεθείτε στο Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Προγραμματισμός και εκτέλεση περιοδικών ενεργειών.", diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f7845b79bf0d..34dd0cb36d7a 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1368,7 +1368,7 @@ "message": "View on Etherscan" }, "expandExperience": { - "message": "Expand your web3 experience" + "message": "Expand your web3 experience with MetaMask Snaps" }, "expandView": { "message": "Expand view" @@ -1410,7 +1410,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "See details", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Added on", @@ -2010,7 +2010,7 @@ "message": "Malformed data" }, "manageSnaps": { - "message": "Manage your installed Snaps" + "message": "Manage your installed snaps" }, "max": { "message": "Max" @@ -2771,15 +2771,15 @@ }, "permission_accessNamedSnap": { "message": "Connect to $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Access the internet.", "description": "The description of the `endowment:network-access` permission." }, "permission_accessSnap": { - "message": "Connect to the $1 Snap.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "message": "Connect to the $1 snap.", + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Schedule and execute periodic actions.", @@ -3016,7 +3016,7 @@ "message": "NFT was successfully removed!" }, "removeSnap": { - "message": "Remove Snap" + "message": "Remove snap" }, "removeSnapConfirmation": { "message": "Are you sure you want to remove $1?", @@ -3425,7 +3425,7 @@ "description": "This is shown when a snap encounters an error. $1 is the error message from the snap, and $2 is the error code." }, "snapInstall": { - "message": "Install Snap" + "message": "Install snap" }, "snapInstallWarningCheck": { "message": "To confirm that you understand, check the box." @@ -3441,7 +3441,7 @@ "message": "This snap is requesting the following permissions:" }, "snapUpdate": { - "message": "Update Snap" + "message": "Update snap" }, "snapUpdateExplanation": { "message": "$1 needs a newer version of your snap.", diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 0f9c3e87b0b1..607a55e1a52f 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Ver detalles", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Añadido el", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Conéctese al complemento de $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Programar y ejecutar acciones periódicas.", diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 31ff1565d92f..cd34633d58d0 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -893,7 +893,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Ver detalles", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Añadido el", diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index d30cbd4d73ad..b23d498d93c5 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Voir les détails", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Ajouté le", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Connexion au Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Planifiez et exécutez des actions périodiques.", diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 019bc2bfa512..437b9876e498 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "विवरण देखें", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "जोड़ा गया", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "$1 स्नैप से कनेक्ट करें।", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "समय-समय पर आने वाले क्रियाओं को शेड्यूल और निष्पादित करें।", diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 3a136c207d14..cd057e434efb 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Lihat detailnya", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Ditambahkan di", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Hubungkan ke Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Jadwalkan dan lakukan tindakan berkala.", diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 47d58c9515bc..1739957a7242 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "詳細を表示", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "追加日", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "$1 スナップに接続します。", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "定期的なアクションのスケジュール設定と実行。", diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 42f3c8dd839c..64ec8d941a00 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "세부 정보 보기", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "추가하기", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "$1 스냅에 연결합니다.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "정기적 활동 예약 및 실행", diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 185a4a129037..0b40cef5f260 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Ver detalhes", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Adicionado em", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Conecte-se ao snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Agende e execute ações periódicas.", diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 3b53778c216e..d35b302c2d3d 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -893,7 +893,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Ver detalhes", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Adicionado em", diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 70f47fda817c..1874fc415a41 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "См. подробности", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Добавлена", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Подключение к спапу $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Планируйте и выполняйте периодические действия.", diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 453324c80b95..5aab2fe6e16d 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Tingnan ang mga detalye", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Dinagdag sa", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Kumonekta sa $1 Snap.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Mag-iskedyul at magsagawa ng mga pana-panahong mga aksyon.", diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 88cc092beb1e..180558fc6ade 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Ayrıntıları gör", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Şu tarihte eklendi:", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "$1 Snap'e bağlan.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Periyodik eylemleri planla ve gerçekleştir.", diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 6d2ed796a866..17e6d233101c 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "Xem chi tiết", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "Đã thêm vào", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "Kết nối với Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Lên lịch và thực hiện các hành động theo định kỳ.", diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index f1b9c8f0d1b2..cf7a16cd7923 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1276,7 +1276,7 @@ }, "flaskSnapSettingsCardButtonCta": { "message": "查看详细信息", - "description": "Call to action a user can take to see more information about the Snap that is installed" + "description": "Call to action a user can take to see more information about the snap that is installed" }, "flaskSnapSettingsCardDateAddedOn": { "message": "添加于", @@ -2573,7 +2573,7 @@ }, "permission_accessSnap": { "message": "连接$1的Snap。", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the Snap." + "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "规划并执行定期操作。", diff --git a/test/e2e/snaps/test-snap-management.spec.js b/test/e2e/snaps/test-snap-management.spec.js index 8286e534ccc8..049cbd22f93a 100644 --- a/test/e2e/snaps/test-snap-management.spec.js +++ b/test/e2e/snaps/test-snap-management.spec.js @@ -140,7 +140,7 @@ describe('Test Snap Management', function () { await driver.delay(1000); // try to remove snap - await driver.clickElement({ text: 'Remove Snap', tag: 'button' }); + await driver.clickElement({ text: 'Remove snap', tag: 'button' }); await driver.delay(1000); // try to click remove on popover From 5998ae21aa6ca835d5d06e85eeea31c0d10f88ab Mon Sep 17 00:00:00 2001 From: Alaa Hadad Date: Wed, 1 Mar 2023 12:45:27 +0400 Subject: [PATCH 18/19] Buy crypto by redirecting to onramp experience on pdapp instead of deposit popover (#17689) * feat: disable deposit popover and replace it with global redirect to onramp on pdapp * feat: remove legacy code for hardcoded onramp providers * fix: remove unused visuals and components related to legacy code of deposit popover * fix: remove unused messages * feat: use a custom hook for all onramps related methods and variables * fix: modify the custom hook implementation to include test networks * fix: remove deprecated file buy-url * fix: remove references for deleted deposit logos * fix: network-controller failing unit test * fix: snapshot loading-swaps-quotes-stories-metadata.test.js.snap * fix: storybook tests * fix: remove unused constatns related to buyable onramp chains * fix: remove unused variables and fix eslint * adding unit test for useRamps custom hook * feat: add comment on the proper usage of useRamps within confirm-page-container component * fix: add unit tests for buy button in token-overview page * fix: add unit test for open the buy crypto URL for a buyable chain ID in token page * feat: add unit test coverage for eth-overview page * fix: update locales --- app/_locales/am/messages.json | 22 - app/_locales/ar/messages.json | 22 - app/_locales/bg/messages.json | 22 - app/_locales/bn/messages.json | 22 - app/_locales/ca/messages.json | 19 - app/_locales/cs/messages.json | 13 - app/_locales/da/messages.json | 22 - app/_locales/de/messages.json | 68 --- app/_locales/el/messages.json | 68 --- app/_locales/en/messages.json | 68 --- app/_locales/es/messages.json | 68 --- app/_locales/es_419/messages.json | 25 - app/_locales/et/messages.json | 22 - app/_locales/fa/messages.json | 22 - app/_locales/fi/messages.json | 22 - app/_locales/fil/messages.json | 19 - app/_locales/fr/messages.json | 68 --- app/_locales/gu/messages.json | 3 - app/_locales/he/messages.json | 22 - app/_locales/hi/messages.json | 68 --- app/_locales/hn/messages.json | 13 - app/_locales/hr/messages.json | 22 - app/_locales/ht/messages.json | 13 - app/_locales/hu/messages.json | 22 - app/_locales/id/messages.json | 68 --- app/_locales/it/messages.json | 64 --- app/_locales/ja/messages.json | 68 --- app/_locales/kn/messages.json | 22 - app/_locales/ko/messages.json | 68 --- app/_locales/lt/messages.json | 22 - app/_locales/lv/messages.json | 22 - app/_locales/ml/messages.json | 3 - app/_locales/mr/messages.json | 3 - app/_locales/ms/messages.json | 22 - app/_locales/nl/messages.json | 13 - app/_locales/no/messages.json | 22 - app/_locales/ph/messages.json | 22 - app/_locales/pl/messages.json | 22 - app/_locales/pt/messages.json | 68 --- app/_locales/pt_BR/messages.json | 25 - app/_locales/pt_PT/messages.json | 3 - app/_locales/ro/messages.json | 22 - app/_locales/ru/messages.json | 68 --- app/_locales/sk/messages.json | 22 - app/_locales/sl/messages.json | 22 - app/_locales/sr/messages.json | 19 - app/_locales/sv/messages.json | 22 - app/_locales/sw/messages.json | 22 - app/_locales/ta/messages.json | 13 - app/_locales/te/messages.json | 3 - app/_locales/th/messages.json | 16 - app/_locales/tl/messages.json | 68 --- app/_locales/tr/messages.json | 68 --- app/_locales/uk/messages.json | 22 - app/_locales/vi/messages.json | 68 --- app/_locales/zh_CN/messages.json | 68 --- app/_locales/zh_TW/messages.json | 36 -- app/scripts/lib/buy-url.test.js | 109 ----- app/scripts/lib/buy-url.ts | 245 ---------- .../files-to-convert.json | 11 - package.json | 1 + shared/constants/network.ts | 443 +----------------- ui/components/app/app-components.scss | 1 - ...onfirm-page-container-content.component.js | 21 +- .../confirm-page-container.component.js | 29 +- .../app/deposit-popover/deposit-popover.js | 240 ---------- ui/components/app/deposit-popover/index.js | 1 - ui/components/app/deposit-popover/index.scss | 16 - .../app/deposit-popover/on-ramp-item.js | 91 ---- .../app/wallet-overview/eth-overview.js | 323 +++++++------ .../app/wallet-overview/eth-overview.test.js | 159 +++++++ .../app/wallet-overview/token-overview.js | 342 ++++++-------- .../wallet-overview/token-overview.test.js | 181 ++++++- ui/components/ui/logo/README.mdx | 6 - .../__snapshots__/logo-moonpay.test.js.snap | 21 - ui/components/ui/logo/logo-coinbasepay.js | 58 --- ui/components/ui/logo/logo-deposit-eth.js | 54 --- ui/components/ui/logo/logo-moonpay.js | 52 -- ui/components/ui/logo/logo-moonpay.test.js | 11 - ui/components/ui/logo/logo-transak.js | 107 ----- ui/components/ui/logo/logo-wyre.js | 47 -- ui/components/ui/logo/logo.stories.js | 10 - ui/helpers/utils/moonpay.test.js | 33 -- ui/helpers/utils/moonpay.ts | 22 - ui/hooks/experiences/useRamps.test.js | 82 ++++ ui/hooks/experiences/useRamps.ts | 37 ++ ui/pages/send/gas-display/gas-display.js | 23 +- ui/selectors/selectors.js | 52 -- ui/store/actionConstants.ts | 2 - ui/store/actions.ts | 25 +- yarn.lock | 23 + 91 files changed, 832 insertions(+), 3897 deletions(-) delete mode 100644 app/scripts/lib/buy-url.test.js delete mode 100644 app/scripts/lib/buy-url.ts delete mode 100644 ui/components/app/deposit-popover/deposit-popover.js delete mode 100644 ui/components/app/deposit-popover/index.js delete mode 100644 ui/components/app/deposit-popover/index.scss delete mode 100644 ui/components/app/deposit-popover/on-ramp-item.js create mode 100644 ui/components/app/wallet-overview/eth-overview.test.js delete mode 100644 ui/components/ui/logo/__snapshots__/logo-moonpay.test.js.snap delete mode 100644 ui/components/ui/logo/logo-coinbasepay.js delete mode 100644 ui/components/ui/logo/logo-deposit-eth.js delete mode 100644 ui/components/ui/logo/logo-moonpay.js delete mode 100644 ui/components/ui/logo/logo-moonpay.test.js delete mode 100644 ui/components/ui/logo/logo-transak.js delete mode 100644 ui/components/ui/logo/logo-wyre.js delete mode 100644 ui/helpers/utils/moonpay.test.js delete mode 100644 ui/helpers/utils/moonpay.ts create mode 100644 ui/hooks/experiences/useRamps.test.js create mode 100644 ui/hooks/experiences/useRamps.ts diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 3497daaf4eb3..d6b92d26f7ac 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -118,12 +118,6 @@ "browserNotSupported": { "message": "ማሰሺያዎት አልተደገፈም..." }, - "buyWithWyre": { - "message": "$1 በ Wyre ይግዙ" - }, - "buyWithWyreDescription": { - "message": "Wyre ክሬዲት ካርድ ተጠቅመው $1 በቀጥታ በ MetaMask መለያዎ ላይ እንዲያስቀምጡ ያስችልዎታል።" - }, "bytes": { "message": "ባይት" }, @@ -166,9 +160,6 @@ "connectingToMainnet": { "message": "ከዋናው የ Ethereum አውታረ መረብ ጋር መገናኘት" }, - "continueToWyre": { - "message": "ወደ Wyre ይቀጥሉ" - }, "contractDeployment": { "message": "የኮንትራት ስምሪት" }, @@ -318,13 +309,6 @@ "general": { "message": "አጠቃላይ" }, - "getEther": { - "message": "Ether ያግኙ" - }, - "getEtherFromFaucet": { - "message": "Ether ከቧንቧ በ$1ያግኙ", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "የ Goerli የሙከራ አውታረ መረብ" }, @@ -766,9 +750,6 @@ "terms": { "message": "የአጠቃቀም ደንቦች" }, - "testFaucet": { - "message": "የሙከራ ቧንቧ" - }, "tips": { "message": "መረጃዎች" }, @@ -887,9 +868,6 @@ "userName": { "message": "የተጣቃሚ ስም" }, - "viewAccount": { - "message": "መለያን ይመልከቱ" - }, "viewContact": { "message": "ዕውቂያን ይመልከቱ" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index 06ba0766e1d0..4fcdad96044a 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -128,12 +128,6 @@ "browserNotSupported": { "message": "متصفحك غير مدعوم..." }, - "buyWithWyre": { - "message": "قم بشراء عملة إيثير بواسطة Wyre" - }, - "buyWithWyreDescription": { - "message": "يتيح لك Wyre استخدام بطاقة ائتمان لإيداع 1$ مباشرة في حساب MetaMask الخاص بك." - }, "bytes": { "message": "بايتات" }, @@ -176,9 +170,6 @@ "connectingToMainnet": { "message": "جارِ الاتصال بشبكة إيثيريوم الرئيسية" }, - "continueToWyre": { - "message": "الاستمرار إلى Wyre" - }, "contractDeployment": { "message": "نشر العقد" }, @@ -327,13 +318,6 @@ "general": { "message": "عام" }, - "getEther": { - "message": "احصل على إيثر" - }, - "getEtherFromFaucet": { - "message": "احصل على الأثير من صنبور مقابل $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "شبكة اختبار Goerli " }, @@ -778,9 +762,6 @@ "terms": { "message": "شروط الاستخدام" }, - "testFaucet": { - "message": "اختبار Faucet" - }, "tips": { "message": "المكافآت" }, @@ -899,9 +880,6 @@ "userName": { "message": "اسم المستخدم" }, - "viewAccount": { - "message": "عرض حساب" - }, "viewContact": { "message": "عرض جهة الاتصال" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 87af188c7280..dcd59943183e 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Браузърът ви не се поддържа ..." }, - "buyWithWyre": { - "message": "Купете $1 с Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre ви позволява да използвате кредитна карта, за да депозирате $1 право във вашата MetaMask сметка." - }, "bytes": { "message": "Байта" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Свързване с главната мрежа Ethereum" }, - "continueToWyre": { - "message": "Продължете към Wyre" - }, "contractDeployment": { "message": "Разгръщане на договор" }, @@ -323,13 +314,6 @@ "general": { "message": "Общ" }, - "getEther": { - "message": "Вземете етер" - }, - "getEtherFromFaucet": { - "message": "Вземете Ether от фосет за $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Тестова мрежа на Goerli" }, @@ -777,9 +761,6 @@ "terms": { "message": "Условия за ползване" }, - "testFaucet": { - "message": "Тест Faucet" - }, "tips": { "message": "Дарения" }, @@ -898,9 +879,6 @@ "userName": { "message": "Потребителско име" }, - "viewAccount": { - "message": "Преглед на профила" - }, "viewContact": { "message": "Преглед на контакта" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index b5fb8017613a..736c1f72f4e9 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "আপনার ব্রাউজার সমর্থিত নয়..." }, - "buyWithWyre": { - "message": "Wyre দিয়ে $1 ক্রয় করুন" - }, - "buyWithWyreDescription": { - "message": "Wyre আপনার MetaMask অ্যাকাউন্টে সরাসরি $1 জমা করতে আপনাকে একটি ক্রেডিট কার্ড ব্যবহার করতে দেয়।" - }, "bytes": { "message": "বাইটস" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "মুখ্য Ethereum নেটওয়ার্কের সাথে সংযোগ করছে" }, - "continueToWyre": { - "message": "Wyre এ অবিরত রাখুন" - }, "contractDeployment": { "message": "কন্ট্র্যাক্ট নিয়োজন" }, @@ -327,13 +318,6 @@ "general": { "message": "সাধারণ" }, - "getEther": { - "message": "ইথার পান" - }, - "getEtherFromFaucet": { - "message": "$1 এর জন্য একটি ফসেট থেকে ইথার পান", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "গোয়েরলি টেস্ট নেটওয়ার্ক" }, @@ -781,9 +765,6 @@ "terms": { "message": "ব্যবহারের শর্তাবলী" }, - "testFaucet": { - "message": "টেস্ট ফসেট" - }, "tips": { "message": "অর্থসাহায্য এবং পরামর্শ" }, @@ -902,9 +883,6 @@ "userName": { "message": "ইউজারনেম" }, - "viewAccount": { - "message": "আ্যাকাউন্ট দেখুন" - }, "viewContact": { "message": "পরিচিতি দেখুন" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 1a285a375b2c..14c6c1a62456 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "El teu navegador no és suportat..." }, - "buyWithWyre": { - "message": "Compra $1 amb Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre et permet utilitzar una targeta de crèdit per dipositar $1 directe al teu compte MetaMask." - }, "cancel": { "message": "Cancel·la" }, @@ -169,9 +163,6 @@ "connectingToMainnet": { "message": "Connectant a Xarxa Principal Ethereum" }, - "continueToWyre": { - "message": "Continua a Wyre" - }, "contractDeployment": { "message": "Desplegament de Contracte" }, @@ -317,13 +308,6 @@ "gasUsed": { "message": "Gas utilitzat" }, - "getEther": { - "message": "Aconsegueix Ether" - }, - "getEtherFromFaucet": { - "message": "Aconsegueix Ether d'una aixeta per $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Xarxa de test Goerli" }, @@ -871,9 +855,6 @@ "userName": { "message": "Nom d'usuari" }, - "viewAccount": { - "message": "Mostra el compte" - }, "viewContact": { "message": "Veure Contacte" }, diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index 0b1b59e53f6d..3b82640c9f61 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -140,13 +140,6 @@ "gasPrice": { "message": "Cena paliva (GWEI)" }, - "getEther": { - "message": "Získejte Ether" - }, - "getEtherFromFaucet": { - "message": "Získejte Ether z faucetu za $1.", - "description": "Displays network name for Ether faucet" - }, "here": { "message": "zde", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -356,9 +349,6 @@ "terms": { "message": "Podmínky použití" }, - "testFaucet": { - "message": "Testovací faucet" - }, "to": { "message": "Komu" }, @@ -399,9 +389,6 @@ "usedByClients": { "message": "Používána různými klienty" }, - "viewAccount": { - "message": "Zobrazit účet" - }, "visitWebSite": { "message": "Navštivte naši stránku" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index c5d56db6dcdb..8826e12633a5 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Din browser er ikke understøttet..." }, - "buyWithWyre": { - "message": "Køb $1 med Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre lader dig bruge et kreditkort til at indbetale $1 på din MetaMask-konto." - }, "bytes": { "message": "Byte" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Forbinder til dit Primære Ethereum Netværk" }, - "continueToWyre": { - "message": "Fortsæt til Wyre" - }, "contractDeployment": { "message": "Kontraktanvendelse" }, @@ -323,13 +314,6 @@ "general": { "message": "Generelt" }, - "getEther": { - "message": "Hent Ether" - }, - "getEtherFromFaucet": { - "message": "Hent Ether fra en hane til $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli-testnetværk" }, @@ -756,9 +740,6 @@ "terms": { "message": "Brugsbetingelser" }, - "testFaucet": { - "message": "Testhane" - }, "tips": { "message": "Donationer" }, @@ -871,9 +852,6 @@ "userName": { "message": "Brugernavn" }, - "viewAccount": { - "message": "Vis konto" - }, "viewContact": { "message": "Vis kontakt" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index e44c433ec81a..3e510284dcca 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -523,38 +523,9 @@ "message": "$1 kaufen", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "1 $ mit Coinbase Pay kaufen", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Sie können mit Ihrem Coinbase-Konto bequem Kryptowährungen kaufen oder überweisen.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "$1 mit MoonPay kaufen", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay unterstützt gängige Zahlungsmethoden, einschließlich Visa, Mastercard, Apple/Google/ Samsung Pay und Banküberweisungen in über 145 Ländern. Token werden auf Ihr MetaMask-Konto eingezahlt." - }, - "buyCryptoWithTransak": { - "message": "$1 mit Transak kaufen", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak unterstützt Kredit- und Debitkarten, Apple Pay, MobiKwik und Banküberweisungen (je nach Standort) in über 100 Ländern. $1-Einzahlungen direkt auf Ihr MetaMask-Konto.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Jetzt kaufen" }, - "buyWithWyre": { - "message": "$1 mit Wyre kaufen" - }, - "buyWithWyreDescription": { - "message": "Einfaches Onboarding für Käufe bis zu 1000 $. Schnelle interaktive Überprüfung von Käufen mit hohem Limit. Unterstützt Debit-/Kreditkarte, Apple Pay, Banküberweisungen. Verfügbar in über 100 Ländern. Einzahlung von Token auf Ihr MetaMask-Konto" - }, "bytes": { "message": "Bytes" }, @@ -733,18 +704,6 @@ "continue": { "message": "Weiter" }, - "continueToCoinbasePay": { - "message": "Weiter zu Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Weiter zu MoonPay" - }, - "continueToTransak": { - "message": "Weiter zur Transaktion" - }, - "continueToWyre": { - "message": "Weiter zu Wyre" - }, "contract": { "message": "Vertrag" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Einzahlung" }, - "depositCrypto": { - "message": "$1 einzahlen", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Mehr erfahren" }, @@ -973,12 +928,6 @@ "details": { "message": "Details" }, - "directDepositCrypto": { - "message": "Direkt $1 einzahlen" - }, - "directDepositCryptoExplainer": { - "message": "Wenn Sie bereits über $1 verfügen, ist eine direkte Einzahlung der schnellste Weg, um $1 auf Ihr Konto einzuzahlen." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” ist deaktiviert, weil es nicht das Minimum einer zehnprozentigen Erhöhung gegenüber der ursprünglichen Gasgebühr erfüllt.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Allgemein" }, - "getEther": { - "message": "Ether holen" - }, - "getEtherFromFaucet": { - "message": "Ether für das $1-Netzwerk von einem Faucet holen.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Zurück" }, @@ -1928,10 +1870,6 @@ "message": "Das native Token dieses Netzwerks ist $1. Dieses Token wird für die Gasgebühr verwendet.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Um mit dezentralen Anwendungen zu interagieren, die MetaMask verwenden, benötigen Sie $1 in Ihrer Wallet.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Brauchen Sie Hilfe? Kontaktieren Sie $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Nutzungsbedingungen" }, - "testFaucet": { - "message": "Testfaucet" - }, "testNetworks": { "message": "Test-Netzwerke" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Anzeigen" }, - "viewAccount": { - "message": " Konto einsehen" - }, "viewAllDetails": { "message": "Alle Details anzeigen" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 1fc07474ba00..985bc70b4b2a 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -523,38 +523,9 @@ "message": "Αγορά $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Αγορά $1 με Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Μπορείτε να αγοράσετε ή να μεταφέρετε εύκολα κρυπτονομίσματα με τον λογαριασμό σας στο Coinbase.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Αγορά $1 με MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay supports popular payment methods, including Visa, Mastercard, Apple / Google / Samsung Pay, and bank transfers in 145+ countries. Tokens deposit into your MetaMask account." - }, - "buyCryptoWithTransak": { - "message": "Αγορά $1 με Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Η Transak υποστηρίζει πιστωτικές και χρεωστικές κάρτες, Apple Pay, MobiKwik και τραπεζικές μεταφορές (ανάλογα με την τοποθεσία) σε περισσότερες από 145 χώρες. Τα $1 κατατίθενται απευθείας στον λογαριασμό σας στο MetaMask.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Αγοράστε Τώρα" }, - "buyWithWyre": { - "message": "Αγοράστε $1 με το Wyre" - }, - "buyWithWyreDescription": { - "message": "Εύκολη ενσωμάτωση για αγορές μέχρι και $ 1000. Γρήγορη διαδραστική επαλήθευση αγοράς υψηλού ορίου. Υποστηρίζει χρεωστικές/πιστωτικές κάρτες, Apple Pay, Τραπεζικές Μεταφορές. Διαθέσιμο σε 100+ χώρες. Καταθέσεις token στον λογαριασμό σας MetaMask" - }, "bytes": { "message": "Bytes" }, @@ -733,18 +704,6 @@ "continue": { "message": "Συνέχεια" }, - "continueToCoinbasePay": { - "message": "Συνέχεια στο Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Συνέχεια στη MoonPay" - }, - "continueToTransak": { - "message": "Συνεχίστε στο Transak" - }, - "continueToWyre": { - "message": "Συνεχίστε στο Wyre" - }, "contract": { "message": "Συμβόλαιο" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Κατάθεση" }, - "depositCrypto": { - "message": "Κατάθεση $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Μάθετε περισσότερα" }, @@ -973,12 +928,6 @@ "details": { "message": "Λεπτομέρειες" }, - "directDepositCrypto": { - "message": "Απευθείας κατάθεση $1" - }, - "directDepositCryptoExplainer": { - "message": "Εάν έχετε ήδη μερικά $1, ο γρηγορότερος τρόπος για να βάλετε $1 στο νέο σας πορτοφόλι είναι η απευθείας κατάθεση." - }, "disabledGasOptionToolTipMessage": { "message": "Το \"1$\" είναι απενεργοποιημένο επειδή δεν πληροί την ελάχιστη αύξηση 10% σε σχέση με τα αρχικά τέλη συναλλαγής.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Γενικά" }, - "getEther": { - "message": "Λάβετε Ether" - }, - "getEtherFromFaucet": { - "message": "Πάρτε Ether από μια πηγή για το $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Μετάβαση Πίσω" }, @@ -1928,10 +1870,6 @@ "message": "Το αρχικό token σε αυτό το δίκτυο είναι το $1. Είναι το token που χρησιμοποιείται για τα τέλη φυσικού αερίου.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Για να αλληλεπιδράσετε με αποκεντρωμένες εφαρμογές χρησιμοποιώντας το MetaMask, θα χρειαστείτε $1 στο πορτοφόλι σας.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Χρειάζεστε βοήθεια; Επικοινωνήστε με $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Όροι παροχής υπηρεσιών" }, - "testFaucet": { - "message": "Έλεγχος Βαλβίδας" - }, "testNetworks": { "message": "Δοκιμαστικά δίκτυα" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Προβολή" }, - "viewAccount": { - "message": "Προβολή λογαριασμού" - }, "viewAllDetails": { "message": "Προβολή όλων των λεπτομερειών" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 34dd0cb36d7a..0aa328fe0ddd 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -530,38 +530,9 @@ "message": "Buy $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Buy $1 with Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "You can easily buy or transfer crypto with your Coinbase account.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Buy $1 with MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay supports popular payment methods, including Visa, Mastercard, Apple / Google / Samsung Pay, and bank transfers in 145+ countries. Tokens deposit into your MetaMask account." - }, - "buyCryptoWithTransak": { - "message": "Buy $1 with Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak supports credit & debit cards, Apple Pay, MobiKwik, and bank transfers (depending on location) in 100+ countries. $1 deposits directly into your MetaMask account.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Buy Now" }, - "buyWithWyre": { - "message": "Buy $1 with Wyre" - }, - "buyWithWyreDescription": { - "message": "Easy onboarding for purchases up to $ 1000. Fast interactive high limit purchase verification. Supports Debit/Credit Card, Apple Pay, Bank Transfers. Available in 100+ countries. Tokens deposit into your MetaMask Account" - }, "bytes": { "message": "Bytes" }, @@ -755,18 +726,6 @@ "continue": { "message": "Continue" }, - "continueToCoinbasePay": { - "message": "Continue to Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Continue to MoonPay" - }, - "continueToTransak": { - "message": "Continue to Transak" - }, - "continueToWyre": { - "message": "Continue to Wyre" - }, "contract": { "message": "Contract" }, @@ -989,10 +948,6 @@ "deposit": { "message": "Deposit" }, - "depositCrypto": { - "message": "Deposit $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Learn more" }, @@ -1104,12 +1059,6 @@ "details": { "message": "Details" }, - "directDepositCrypto": { - "message": "Directly deposit $1" - }, - "directDepositCryptoExplainer": { - "message": "If you already have some $1, the quickest way to get $1 in your new wallet by direct deposit." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” is disabled because it does not meet the minimum of a 10% increase from the original gas fee.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1566,13 +1515,6 @@ "general": { "message": "General" }, - "getEther": { - "message": "Get Ether" - }, - "getEtherFromFaucet": { - "message": "Get Ether from a faucet for the $1 network.", - "description": "Displays network name for Ether faucet" - }, "getWarningsFromOpenSea": { "message": "Get warnings from OpenSea whenever you receive a known malicious request." }, @@ -2103,10 +2045,6 @@ "message": "The native token on this network is $1. It is the token used for gas fees.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "To interact with decentralized applications using MetaMask, you’ll need $1 in your wallet.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Need help? Contact $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -4083,9 +4021,6 @@ "termsOfService": { "message": "Terms of service" }, - "testFaucet": { - "message": "Test faucet" - }, "testNetworks": { "message": "Test networks" }, @@ -4458,9 +4393,6 @@ "view": { "message": "View" }, - "viewAccount": { - "message": "View account" - }, "viewAllDetails": { "message": "View all details" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 607a55e1a52f..d87e7b7f5450 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -523,38 +523,9 @@ "message": "Comprar $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Comprar $1 con Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Puede comprar o transferir criptomonedas fácilmente por medio de su cuenta de Coinbase.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Comprar $1 con MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay admite métodos de pago populares, incluidos Visa, Mastercard, Apple/Google/Samsung Pay y transferencias bancarias en más de 145 países. Depósito de tokens en su cuenta MetaMask." - }, - "buyCryptoWithTransak": { - "message": "Comprar $1 con Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak admite tarjetas de crédito y débito, Apple Pay, MobiKwik y transferencias bancarias (según la ubicación) en más de 100 países. Depósitos de $1 directamente en su cuenta MetaMask.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Comprar ahora" }, - "buyWithWyre": { - "message": "Comprar $1 con Wyre" - }, - "buyWithWyreDescription": { - "message": "Acceso fácil a compras de hasta $1,000. Verificación interactiva rápida de compra de límite alto. Acepta tarjeta de débito/crédito, Apple Pay y transferencias bancarias. Disponible para más de 100 países. Los tokens se depositarán en su cuenta MetaMask" - }, "bytes": { "message": "Bytes" }, @@ -733,18 +704,6 @@ "continue": { "message": "Continuar" }, - "continueToCoinbasePay": { - "message": "Continuar a Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Continuar a MoonPay" - }, - "continueToTransak": { - "message": "Continuar a Transak" - }, - "continueToWyre": { - "message": "Continuar a Wyre" - }, "contract": { "message": "Contrato" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Depositar" }, - "depositCrypto": { - "message": "Deposite $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Más información" }, @@ -973,12 +928,6 @@ "details": { "message": "Detalles" }, - "directDepositCrypto": { - "message": "Deposite directamente $1" - }, - "directDepositCryptoExplainer": { - "message": "Si ya tiene algo de $1, la forma más rápida de obtener $1 en su nueva billetera mediante depósito directo." - }, "disabledGasOptionToolTipMessage": { "message": "\"1$\" está desactivado porque no cumple el mínimo de un aumento del 10% respecto a la tarifa de gas original.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "General" }, - "getEther": { - "message": "Obtener ether" - }, - "getEtherFromFaucet": { - "message": "Obtenga Ether de un faucet para la red de $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Volver" }, @@ -1928,10 +1870,6 @@ "message": "El token nativo en esta red es de $1. Es el token utilizado para las tarifas de gas.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Para interactuar con aplicaciones descentralizadas usando MetaMask, necesitará $1 en su billetera.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "¿Necesita ayuda? Comuníquese con $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Términos de servicio" }, - "testFaucet": { - "message": "Faucet de prueba" - }, "testNetworks": { "message": "Redes de prueba" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Ver" }, - "viewAccount": { - "message": "Ver cuenta" - }, "viewAllDetails": { "message": "Ver todos los detalles" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index cd34633d58d0..2a4ffbb8ebcb 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -317,12 +317,6 @@ "buy": { "message": "Comprar" }, - "buyWithWyre": { - "message": "Comprar $1 con Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre le permite usar una tarjeta de débito para depositar $1 directamente en su cuenta de MetaMask." - }, "bytes": { "message": "Bytes" }, @@ -469,12 +463,6 @@ "continue": { "message": "Continuar" }, - "continueToTransak": { - "message": "Continuar a Transak" - }, - "continueToWyre": { - "message": "Continuar a Wyre" - }, "contract": { "message": "Contrato" }, @@ -1030,13 +1018,6 @@ "general": { "message": "General" }, - "getEther": { - "message": "Obtener ether" - }, - "getEtherFromFaucet": { - "message": "Obtener ether de un faucet para $1", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Volver" }, @@ -2604,9 +2585,6 @@ "termsOfService": { "message": "Términos de servicio" }, - "testFaucet": { - "message": "Probar faucet" - }, "time": { "message": "Tiempo" }, @@ -2866,9 +2844,6 @@ "message": "Verifique este token en $1 y asegúrese de que sea el token con el que quiere realizar la transacción.", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, - "viewAccount": { - "message": "Ver cuenta" - }, "viewAllDetails": { "message": "Ver todos los detalles" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 401cf7956376..59aefc86c175 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Teie lehitsejat ei toetata..." }, - "buyWithWyre": { - "message": "Ostke $1 -d Wyre'iga" - }, - "buyWithWyreDescription": { - "message": "Wyre võimaldab kasutada krediitkaarti, et teha $1 sissemakse otse MetaMaski kontole." - }, "bytes": { "message": "Baidid" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Ühenduse loomine peamise Etherumi võrguga" }, - "continueToWyre": { - "message": "Ava Wyre" - }, "contractDeployment": { "message": "Lepingu juurutamine" }, @@ -323,13 +314,6 @@ "general": { "message": "Üldine teave" }, - "getEther": { - "message": "Hankige eetrit" - }, - "getEtherFromFaucet": { - "message": "Hankige kraanist eetrit $1eest", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli testvõrk" }, @@ -771,9 +755,6 @@ "terms": { "message": "Teenusetingimused" }, - "testFaucet": { - "message": "Testkraan" - }, "tips": { "message": "Preemiad" }, @@ -892,9 +873,6 @@ "userName": { "message": "Kasutajanimi" }, - "viewAccount": { - "message": "Kuva konto" - }, "viewContact": { "message": "Kuva kontakt" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index c8522b810f9a..9603c04f370e 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "مرورگر شما پشتیبانی نمیشود" }, - "buyWithWyre": { - "message": "$1 را توسط Wyre خریداری نمایید" - }, - "buyWithWyreDescription": { - "message": "Wyre به شما اجازه میدهد تا یک کردیت کارت را جهت پرداخت 1$ مستقیمًا به حساب MetaMask تان استفاده نمایید." - }, "bytes": { "message": "بایت ها" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "در حال اتصال به شبکه اصلی ایتریم" }, - "continueToWyre": { - "message": "ادامه به Wyre" - }, "contractDeployment": { "message": "تطبیق قرارداد" }, @@ -327,13 +318,6 @@ "general": { "message": "عمومی" }, - "getEther": { - "message": "اتر را بگیرید" - }, - "getEtherFromFaucet": { - "message": "اخذ ایتر از یک فاست برای 1$1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "شبکه آزمایشی Goerli" }, @@ -781,9 +765,6 @@ "terms": { "message": "شرایط استفاده" }, - "testFaucet": { - "message": " آزمایش فاسیت یا Test Faucet " - }, "tips": { "message": "انعام" }, @@ -902,9 +883,6 @@ "userName": { "message": "نام کاربری" }, - "viewAccount": { - "message": "مشاهده حساب" - }, "viewContact": { "message": "مشاهده تماس" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index b7f560918fd7..2ba49aee4b6e 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Selaintasi ei tueta..." }, - "buyWithWyre": { - "message": "Osta $1 :ta Wyrella" - }, - "buyWithWyreDescription": { - "message": "Wyre antaa sinun käyttää luottokorttia, jotta voit tallettaa $1 :ta suoraan MetaMask-tilillesi." - }, "bytes": { "message": "Tavua" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Yhdistetään Ethereumin pääverkkoon" }, - "continueToWyre": { - "message": "Jatka Wyreen" - }, "contractDeployment": { "message": "Sopimuksen käyttö" }, @@ -327,13 +318,6 @@ "general": { "message": "Yleistä" }, - "getEther": { - "message": "Hanki Etheriä" - }, - "getEtherFromFaucet": { - "message": "Hanki etheriä faucetista kohteelle $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli-testiverkko" }, @@ -778,9 +762,6 @@ "terms": { "message": "Käyttöehdot" }, - "testFaucet": { - "message": "Koe-faucet" - }, "tips": { "message": "Tipit" }, @@ -899,9 +880,6 @@ "userName": { "message": "Käyttäjätunnus" }, - "viewAccount": { - "message": "Näytä tili" - }, "viewContact": { "message": "Näytä yhteyshenkilö" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 8193ed85256a..a8262f9aee17 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -109,12 +109,6 @@ "browserNotSupported": { "message": "Hindi sinusuportahan ang iyong Browser..." }, - "buyWithWyre": { - "message": "Bumili ng $1 gamit ang Wyre" - }, - "buyWithWyreDescription": { - "message": "Binibigyang-daan ka ng Wyre na gumamit ng credit card para magdeposito ng $1 nang direkta sa iyong MetaMask account." - }, "cancel": { "message": "Kanselahin" }, @@ -151,9 +145,6 @@ "connectingToMainnet": { "message": "Kumokonekta sa Ethereum Mainnet" }, - "continueToWyre": { - "message": "Magpatuloy sa Wyre" - }, "contractDeployment": { "message": "Deployment ng Contract" }, @@ -296,13 +287,6 @@ "general": { "message": "Pangkalahatan" }, - "getEther": { - "message": "Kumuha ng Ether" - }, - "getEtherFromFaucet": { - "message": "Kumuha ng Ether mula sa isang faucet para sa $1", - "description": "Displays network name for Ether faucet" - }, "hardwareWalletConnected": { "message": "Nakakonekta ang hardware wallet" }, @@ -811,9 +795,6 @@ "usedByClients": { "message": "Ginagamit ng iba't ibang client" }, - "viewAccount": { - "message": "Tingnan ang Account" - }, "viewContact": { "message": "Tingnan ang Contact" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index b23d498d93c5..c23b96fee8ee 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -523,38 +523,9 @@ "message": "Acheter $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Achetez des $1 avec Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Vous pouvez facilement acheter et transférer des cryptomonnaies en utilisant votre compte Coinbase.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Acheter $1 avec MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay prend en charge les moyens de paiement populaires, incluant Visa, Mastercard, Apple / Google / Samsung Pay et les virements bancaires dans plus de 145 pays. Les tokens sont déposés sur votre compte MetaMask." - }, - "buyCryptoWithTransak": { - "message": "Acheter $1 avec Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak prend en charge les cartes de crédit et de débit, Apple Pay, MobiKwik et les virements bancaires (selon l’emplacement) dans plus de 100 pays. Les tokens $1 sont directement déposés sur votre compte MetaMask.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Achetez maintenant" }, - "buyWithWyre": { - "message": "Acheter des $1 avec Wyre" - }, - "buyWithWyreDescription": { - "message": "Intégration facile pour les achats à hauteur de 1000 $. Vérification interactive et rapide des achats pour les comptes qui bénéficient d’un plafond de paiement élevé. Prise en charge des cartes de débit/crédit, d’Apple Pay et des virements bancaires. Disponible dans plus de 100 pays. Dépôt de jetons sur votre compte MetaMask." - }, "bytes": { "message": "Octets" }, @@ -733,18 +704,6 @@ "continue": { "message": "Continuer" }, - "continueToCoinbasePay": { - "message": "Accéder à Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Continuer vers MoonPay" - }, - "continueToTransak": { - "message": "Continuer vers Transak" - }, - "continueToWyre": { - "message": "Continuer vers Wyre" - }, "contract": { "message": "Contrat" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Effectuez un dépôt" }, - "depositCrypto": { - "message": "Effectuer un dépôt de $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "En savoir plus" }, @@ -973,12 +928,6 @@ "details": { "message": "Détails" }, - "directDepositCrypto": { - "message": "Déposer directement $1" - }, - "directDepositCryptoExplainer": { - "message": "Si vous avez déjà un peu de $1, la façon la plus rapide d’obtenir $1 dans votre nouveau portefeuille est par dépôt direct." - }, "disabledGasOptionToolTipMessage": { "message": "« $1 » est désactivé parce qu’il ne correspond pas au minimum d’augmentation de 10 % par rapport aux gas fees initiaux.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Général" }, - "getEther": { - "message": "Obtenir des Ether" - }, - "getEtherFromFaucet": { - "message": "Obtenir de l’Ether d’un faucet pour le réseau $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Retour" }, @@ -1928,10 +1870,6 @@ "message": "Le jeton natif de ce réseau est $1. C’est le jeton utilisé pour les frais de gaz.\n", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Pour interagir avec des applications décentralisées à l’aide de MetaMask, vous devrez avoir $1 dans votre portefeuille.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Vous avez besoin d’aide ? Contactez $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Conditions de service" }, - "testFaucet": { - "message": "Faucet testnet" - }, "testNetworks": { "message": "Réseaux de test" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Affichez" }, - "viewAccount": { - "message": "Voir le compte" - }, "viewAllDetails": { "message": "Afficher tous les détails" }, diff --git a/app/_locales/gu/messages.json b/app/_locales/gu/messages.json index 59b79519e473..91c0cb076f8e 100644 --- a/app/_locales/gu/messages.json +++ b/app/_locales/gu/messages.json @@ -144,8 +144,5 @@ }, "userName": { "message": "વપરાશકર્તાનામ" - }, - "viewAccount": { - "message": "એકાઉન્ટ જુઓ" } } diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 67e88b498987..646efc5b6fcf 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "הדפדפן שלך אינו נתמך..." }, - "buyWithWyre": { - "message": "רכישת את'ר עם Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre מאפשרת לך להשתמש בכרטיס אשראי כדי להפקיד $1 ישירות בחשבון ה-MetaMask שלך." - }, "bytes": { "message": "בייטים" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "מתחבר לרשת אתריום הראשית" }, - "continueToWyre": { - "message": "המשך ל-Wyre" - }, "contractDeployment": { "message": "שליחת חוזה (Contract Deployment)" }, @@ -327,13 +318,6 @@ "general": { "message": "כללי" }, - "getEther": { - "message": "השג/י את'ר" - }, - "getEtherFromFaucet": { - "message": "השג/י את'ר מברז (faucet) עבור ה-$1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "רשת בדיקה Goerli " }, @@ -778,9 +762,6 @@ "terms": { "message": "תנאי שימוש" }, - "testFaucet": { - "message": "בדיקת ברז (Faucet)" - }, "tips": { "message": "טיפים" }, @@ -899,9 +880,6 @@ "userName": { "message": "שם משתמש" }, - "viewAccount": { - "message": "הצג חשבון" - }, "viewContact": { "message": "הצג איש קשר" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 437b9876e498..755c922e8725 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -523,38 +523,9 @@ "message": "$1 खरीदें", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "कॉइनबेस पे से $1 खरीदें", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "अपने कॉइनबेस अकाउंट के साथ आप क्रिप्टो को आसानी से खरीद या ट्रांसफर कर सकते हैं।", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "MoonPay से $1 खरीदें", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay कई लोकप्रिय भुगतान विधियों को सपोर्ट करता है, जिसमें Visa, Mastercard, Apple / Google / Samsung Pay और 145+ देशों में बैंक हस्तांतरण शामिल हैं। टोकन आपके MetaMask के अकाउंट में जमा होते हैं।" - }, - "buyCryptoWithTransak": { - "message": "Transak से $1 खरीदें", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak 100+ देशों में क्रेडिट और डेबिट कार्ड, Apple Pay, MobiKwik और बैंक ट्रांसफ़र (स्थान के आधार पर) को सपोर्ट करता है। $1 सीधे आपके MetaMask के अकाउंट में जमा होता है।", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "अभी खरीदें" }, - "buyWithWyre": { - "message": "Wyre के साथ $1 खरीदें" - }, - "buyWithWyreDescription": { - "message": "$1000 तक की खरीदारी के लिए आसान ऑनबोर्डिंग। तेज़ इंटरैक्टिव उच्च सीमा खरीद सत्यापन। डेबिट / क्रेडिट कार्ड, ऐप्पल पे, बैंक ट्रांसफर का समर्थन करता है। 100+ देशों में उपलब्ध है। टोकन आपके मेटामास्क खाते में जमा होते हैं" - }, "bytes": { "message": "बाइट" }, @@ -733,18 +704,6 @@ "continue": { "message": "जारी रखें" }, - "continueToCoinbasePay": { - "message": "कॉइनबेस-पे पर जारी रहें" - }, - "continueToMoonPay": { - "message": "MoonPay के लिए जारी रखें" - }, - "continueToTransak": { - "message": "Transak के लिए जारी रखें" - }, - "continueToWyre": { - "message": "Wyre पर जारी रखें" - }, "contract": { "message": "अनुबंध" }, @@ -957,10 +916,6 @@ "deposit": { "message": "जमा करें" }, - "depositCrypto": { - "message": "$1 जमा करें", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "अधिक जानें" }, @@ -973,12 +928,6 @@ "details": { "message": "विस्तृत जानकारी" }, - "directDepositCrypto": { - "message": "$1 सीधे जमा करें" - }, - "directDepositCryptoExplainer": { - "message": "यदि आपके पास कुछ $1 पहले से हैं, तो अपने नए वॉलेट में $1 प्राप्त करने का सबसे तेज़ तरीका है सीधे जमा करना है।" - }, "disabledGasOptionToolTipMessage": { "message": "\"$1\" अक्षम किया गया है क्योंकि यह मूल गैस शुल्क से न्यूनतम 10% वृद्धि को पूरा नहीं करता है।", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "सामान्य" }, - "getEther": { - "message": "Ether प्राप्त करें" - }, - "getEtherFromFaucet": { - "message": "$1 के लिए एक फॉसेट से Ether प्राप्त करें", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "वापस जाएं" }, @@ -1928,10 +1870,6 @@ "message": "इस नेटवर्क पर मूल टोकन $1 है। यह गैस शुल्क के लिए इस्तेमाल किया जाने वाला टोकन है।", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "MetaMask का इस्तेमाल करते हुए विकेंद्रीकृत एप्लिकेशन्स के साथ इंटरैक्ट करने के लिए आपके वॉलेट में $1 होना ज़रूरी है।", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "मदद चाहिए? $1 से संपर्क करें", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "सेवा की शर्तें" }, - "testFaucet": { - "message": "फॉसेट का परीक्षण करें" - }, "testNetworks": { "message": "टेस्ट नेटवर्क्स" }, @@ -4166,9 +4101,6 @@ "view": { "message": "देखें" }, - "viewAccount": { - "message": "अकाउंट देखें" - }, "viewAllDetails": { "message": "सभी विवरण देखें" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index 6071dc3d3b05..f94ab181c90d 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -122,13 +122,6 @@ "gasPrice": { "message": "गैस मूल्य (जीडब्ल्यूईआई),(GWEI)" }, - "getEther": { - "message": "ईथर प्राप्त करें" - }, - "getEtherFromFaucet": { - "message": "$1 के लिए एक नल से ईथर प्राप्त करें", - "description": "Displays network name for Ether faucet" - }, "here": { "message": "यहां", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -318,9 +311,6 @@ "terms": { "message": "उपयोग की शर्तें" }, - "testFaucet": { - "message": "टेस्ट नलि" - }, "to": { "message": "के लिए" }, @@ -355,9 +345,6 @@ "usedByClients": { "message": "विभिन्न क्लाइंट्स द्वारा उपयोग किया जाता है" }, - "viewAccount": { - "message": "खाता देखें" - }, "visitWebSite": { "message": "हमारी वेब साइट पर जाएं" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 5aa70285de05..9aed6392c2a7 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Vaš se preglednik ne podržava..." }, - "buyWithWyre": { - "message": "Kupi $1 Wyerom" - }, - "buyWithWyreDescription": { - "message": "Wyreom vam se omogućava korištenje kreditnom karticom za polaganje $1 -a izravno na vaš račun za MetaMask." - }, "bytes": { "message": "Bajtovi" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Povezivanje na glavnu mrežu Ethereum" }, - "continueToWyre": { - "message": "Nastavi na uslugu Wyre" - }, "contractDeployment": { "message": "Primjena ugovora" }, @@ -323,13 +314,6 @@ "general": { "message": "Opće" }, - "getEther": { - "message": "Dohvati Ether" - }, - "getEtherFromFaucet": { - "message": "Dohvati Ether iz svežnja za $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Testna mreža Goerli" }, @@ -774,9 +758,6 @@ "terms": { "message": "Odredbe uporabe" }, - "testFaucet": { - "message": "Testni snop" - }, "tips": { "message": "Napojnice" }, @@ -892,9 +873,6 @@ "userName": { "message": "Korisničko ime" }, - "viewAccount": { - "message": "Prikaz računa" - }, "viewContact": { "message": "Prikaži kontakt" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 89f56b1aafdc..5b1aaf04f9d2 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -200,13 +200,6 @@ "gasUsed": { "message": "Gaz yo Itilize" }, - "getEther": { - "message": "Jwenn Ether" - }, - "getEtherFromFaucet": { - "message": "Jwenn Ether nan yon tiyo pou $1 la", - "description": "Displays network name for Ether faucet" - }, "hardware": { "message": "materyèl" }, @@ -537,9 +530,6 @@ "terms": { "message": "Tèm pou itilize" }, - "testFaucet": { - "message": "Tès Tiyo" - }, "to": { "message": "Pou" }, @@ -619,9 +609,6 @@ "usedByClients": { "message": "Itilize pa yon varyete de kliyan diferan" }, - "viewAccount": { - "message": "Wè Kont" - }, "visitWebSite": { "message": "Vizite sit entènèt nou an" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index d33d01639316..7a48cf68ace3 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Az ön böngészője nem támogatott..." }, - "buyWithWyre": { - "message": "Vásároljon $1 -t a Wyre-rel" - }, - "buyWithWyreDescription": { - "message": "A Wyre segítségével egyensen a MetaMaks fiókjában tehet letétbe ETH-t." - }, "bytes": { "message": "Bájtok" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Csatlakozás a fő Ethereum hálózathoz" }, - "continueToWyre": { - "message": "Tovább a Wyre-re" - }, "contractDeployment": { "message": "Szerződés alkalmazása" }, @@ -323,13 +314,6 @@ "general": { "message": "Általános" }, - "getEther": { - "message": "Ether beszerzése" - }, - "getEtherFromFaucet": { - "message": "Szerezzen Ethert pénzcsapból a(z) $1-ért", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli teszthálózat" }, @@ -774,9 +758,6 @@ "terms": { "message": "Használati feltételek" }, - "testFaucet": { - "message": "Teszt csap" - }, "tips": { "message": "Adományok" }, @@ -892,9 +873,6 @@ "userName": { "message": "Felhasználónév" }, - "viewAccount": { - "message": "Fiók megtekintése" - }, "viewContact": { "message": "Névjegy megtekintése" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index cd057e434efb..c34fb916ae58 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -523,38 +523,9 @@ "message": "Beli $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Beli $1 melalui Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Anda dapat dengan mudah membeli atau mentransfer kripto dengan akun Coinbase Anda.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Beli $1 melalui MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay mendukung metode pembayaran populer, termasuk Visa, Mastercard, Apple/Google/Samsung Pay, dan transfer bank di 145+ negara. Token akan didepositokan ke akun MetaMask Anda." - }, - "buyCryptoWithTransak": { - "message": "Beli $1 melalui Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak mendukung kartu kredit & debit, Apple Pay, MobiKwik, dan transfer bank (tergantung lokasi) di 100+ negara. $1 akan langsung didepositokan ke akun MetaMask Anda.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Beli Sekarang" }, - "buyWithWyre": { - "message": "Beli $1 dengan Wyre" - }, - "buyWithWyreDescription": { - "message": "Orientasi mudah untuk pembelian hingga $ 1000. Verifikasi pembelian limit tinggi interaktif yang cepat. Mendukung Kartu Debit/Kredit, Apple Pay, Transfer Bank. Tersedia di 100+ negara. Token disetor ke Akun MetaMask Anda" - }, "bytes": { "message": "Byte" }, @@ -733,18 +704,6 @@ "continue": { "message": "Lanjutkan" }, - "continueToCoinbasePay": { - "message": "Lanjutkan ke Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Lanjutkan ke MoonPay" - }, - "continueToTransak": { - "message": "Lanjutkan ke Transak" - }, - "continueToWyre": { - "message": "Lanjutkan ke Wyre" - }, "contract": { "message": "Kontrak" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Deposit" }, - "depositCrypto": { - "message": "Deposit $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Pelajari selengkapnya" }, @@ -973,12 +928,6 @@ "details": { "message": "Detail" }, - "directDepositCrypto": { - "message": "Deposit langsung $1" - }, - "directDepositCryptoExplainer": { - "message": "Jika sudah memiliki $1, cara tercepat mendapatkan $1 di dompet baru Anda adalah dengan deposit langsung." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” dinonaktifkan karena tidak memenuhi kenaikan minimum 10% dari biaya gas asli.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Umum" }, - "getEther": { - "message": "Dapatkan Ether" - }, - "getEtherFromFaucet": { - "message": "Dapatkan Ether dari keran untuk jaringan $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Kembali" }, @@ -1928,10 +1870,6 @@ "message": "Token asli di jaringan ini adalah $1. Ini merupakan token yang digunakan untuk biaya gas.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Untuk berinteraksi dengan aplikasi terdesentralisasi menggunakan MetaMask, Anda memerlukan $1 di dompet.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Butuh bantuan? Hubungi $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Ketentuan layanan" }, - "testFaucet": { - "message": "Uji fungsi" - }, "testNetworks": { "message": "Jaringan pengujian" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Lihat" }, - "viewAccount": { - "message": "Lihat akun" - }, "viewAllDetails": { "message": "Lihat semua detail" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index df6b077d85e4..4e5fe8a4aea2 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -408,35 +408,6 @@ "message": "Compra $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Compra $1 con Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Puoi facilmente acquistare o trasferire criptovalute con il tuo account Coinbase.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Compra $1 con MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay supporta metodi di pagamento popolari, incluso Visa, Mastercard, Apple / Google / Samsung Pay e bonifici bancari in 145+ paesi. I Token vengono depositati nel tuo account MetaMask." - }, - "buyCryptoWithTransak": { - "message": "Compra $1 con Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak supporta carte di credito e debito, Apple Pay, MobiKwik e bonifici bancari (in base alla località) in 100+ paesi. Deposita $1 direttamente nel tuo account MetaMask.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyWithWyre": { - "message": "Compra $1 con Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre ti consente di usare la carta di credito per depositare $1 direttamente nel tuo account MetaMask." - }, "canToggleInSettings": { "message": "Puoi riabilitare questa notifica in Impostazioni -> Avvisi." }, @@ -595,18 +566,6 @@ "continue": { "message": "Continua" }, - "continueToCoinbasePay": { - "message": "Continua su Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Continua su MoonPay" - }, - "continueToTransak": { - "message": "Continua su Transak" - }, - "continueToWyre": { - "message": "Continua su Wyre" - }, "contract": { "message": "Contratto" }, @@ -792,10 +751,6 @@ "deleteNetworkDescription": { "message": "Sei sicuro di voler eliminare questa rete?" }, - "depositCrypto": { - "message": "Deposita $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Scopri di più" }, @@ -808,12 +763,6 @@ "details": { "message": "Dettagli" }, - "directDepositCrypto": { - "message": "Deposito diretto $1" - }, - "directDepositCryptoExplainer": { - "message": "Se hai già $1, il modo più rapido per ottenere $1 nel tuo nuovo portafoglio tramite deposito diretto." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” è disabilitato perché non soddisfa la maggiorazione minima del 10% rispetto al canone gas originario.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1040,13 +989,6 @@ "general": { "message": "Generale" }, - "getEther": { - "message": "Ottieni Ether" - }, - "getEtherFromFaucet": { - "message": "Ottieni Get Ether da un faucet per $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Rete di test Goerli" }, @@ -1855,9 +1797,6 @@ "termsOfService": { "message": "Termini di Servizio" }, - "testFaucet": { - "message": "Prova Faucet" - }, "tips": { "message": "Suggerimenti" }, @@ -1997,9 +1936,6 @@ "message": "Verifica questo token su $1", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, - "viewAccount": { - "message": "Vedi Account" - }, "viewAllDetails": { "message": "Vedi tutti i dettagli" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 1739957a7242..8f69950fa4d6 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -523,38 +523,9 @@ "message": "$1 を購入", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Coinbase Pay で $1 を購入", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Coinbase アカウントで簡単に仮想通貨を購入または送金できます。", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "MoonPay で $1 を購入", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay は 145 か国以上で、Visa、Mastercard、Apple / Google / Samsung Pay、銀行送金などの一般的な支払方法に対応しています。トークンは MetaMask アカウントに入金されます。" - }, - "buyCryptoWithTransak": { - "message": "Transak で $1 を購入", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak は、100 か国以上でクレジット・デビットカード、Apple Pay、MobiKwik、銀行送金 (場所による) に対応しています。$1 は MetaMask アカウントに直接入金されます。", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "今すぐ購入" }, - "buyWithWyre": { - "message": "Wyreで$1を購入" - }, - "buyWithWyreDescription": { - "message": "簡単なオンボーディングプロセスで最高 $ 1000 購入可能。迅速かつインタラクティブな高限度額の購入検証。デビット・クレジットカード、Apple Pay、銀行送金に対応。100か国以上で利用可能。トークンは MetaMask アカウントに入金されます。" - }, "bytes": { "message": "バイト" }, @@ -733,18 +704,6 @@ "continue": { "message": "続行" }, - "continueToCoinbasePay": { - "message": "Coinbase Pay に進む" - }, - "continueToMoonPay": { - "message": "MoonPay に進む" - }, - "continueToTransak": { - "message": "Transakに進む" - }, - "continueToWyre": { - "message": "Wyreに進む" - }, "contract": { "message": "コントラクト" }, @@ -957,10 +916,6 @@ "deposit": { "message": "入金" }, - "depositCrypto": { - "message": "$1 を入金", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "詳細" }, @@ -973,12 +928,6 @@ "details": { "message": "詳細" }, - "directDepositCrypto": { - "message": "$1 を直接入金" - }, - "directDepositCryptoExplainer": { - "message": "すでに $1 をお持ちの場合、新しいウォレットに最も素早く $1 を入金する方法が、直接入金です。" - }, "disabledGasOptionToolTipMessage": { "message": "元のガス代の 10% 以上という増額の条件を満たしていないため、「$1」は利用できません。", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "一般" }, - "getEther": { - "message": "Etherを取得" - }, - "getEtherFromFaucet": { - "message": "$1 ネットワークのフォーセットから Ether を取得", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "戻る" }, @@ -1928,10 +1870,6 @@ "message": "このネットワークのネイティブトークンは $1 です。ガス代にもこのトークンが使用されます。", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "MetaMask で分散型アプリケーションとやり取りするには、ウォレットに $1 が必要です。", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "アシスタンスが必要な場合は、$1にお問い合わせください", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "サービス規約" }, - "testFaucet": { - "message": "テストフォーセット" - }, "testNetworks": { "message": "テストネットワーク" }, @@ -4166,9 +4101,6 @@ "view": { "message": "表示" }, - "viewAccount": { - "message": "アカウントを表示" - }, "viewAllDetails": { "message": "すべての詳細の表示" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 08eeb00a568d..42de7215fa94 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "ನಿಮ್ಮ ಬ್ರೌಸರ್ ಬೆಂಬಲಿಸುತ್ತಿಲ್ಲ..." }, - "buyWithWyre": { - "message": "Wyre ನೊಂದಿಗೆ $1 ಖರೀದಿಸಿ" - }, - "buyWithWyreDescription": { - "message": "ನಿಮ್ಮ MetaMask ಖಾತೆಗೆ $1 ಅನ್ನು ಜಮಾ ಮಾಡಲು ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಬಳಸಲು Wyre ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ." - }, "bytes": { "message": "ಬೈಟ್‌ಗಳು" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "ಮುಖ್ಯ ಎಥೆರಿಯಮ್ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ" }, - "continueToWyre": { - "message": "Wyre ಗೆ ಮುಂದುವರಿಸಿ" - }, "contractDeployment": { "message": "ಒಪ್ಪಂದದ ನಿಯೋಜನೆ" }, @@ -327,13 +318,6 @@ "general": { "message": "ಸಾಮಾನ್ಯ" }, - "getEther": { - "message": "ಎಥರ್ ಪಡೆಯಿರಿ" - }, - "getEtherFromFaucet": { - "message": "$1 ಗಾಗಿ ಫಾಸೆಟ್‌ನಿಂದ ಎಥರ್ ಅನ್ನು ಪಡೆಯಿರಿ", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli ಪರೀಕ್ಷೆ ನೆಟ್‌ವರ್ಕ್" }, @@ -781,9 +765,6 @@ "terms": { "message": "ಬಳಕೆಯ ನಿಯಮಗಳು" }, - "testFaucet": { - "message": "ಫಾಸೆಟ್ ಪರೀಕ್ಷಿಸಿ" - }, "tips": { "message": "ಸಲಹೆಗಳು" }, @@ -902,9 +883,6 @@ "userName": { "message": "ಬಳಕೆದಾರಹೆಸರು" }, - "viewAccount": { - "message": "ಖಾತೆಯನ್ನು ವೀಕ್ಷಿಸಿ" - }, "viewContact": { "message": "ಸಂಪರ್ಕವನ್ನು ವೀಕ್ಷಿಸಿ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 64ec8d941a00..36b5a9738d3c 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -523,38 +523,9 @@ "message": "$1 구매", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Coinbase Pay로 $1 구매", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Coinbase 계정으로 손쉽게 암호화폐를 구매하거나 전송할 수 있습니다.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "문페이(MoonPay)로 $1 구매", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "문페이는 비자, 마스터카드, 애플/구글/삼성 페이, 145개국 이상에서 이용 가능한 은행 송금을 비롯해 다양한 결제 방법을 지원합니다. 토큰은 MetaMask 계정에 입금됩니다." - }, - "buyCryptoWithTransak": { - "message": "트랜삭(Transak)으로 $1 구매", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "트랜삭은 100개국 이상에서 신용카드, 직불카드, 애플 페이, 모비퀵, 은행 송금(지역에 따라 지원이 안 될 수 있음)을 지원합니다. $1 입금은 MetaMask 계정으로 직접 처리됩니다.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "지금 구매" }, - "buyWithWyre": { - "message": "Wyre로 $1 구매" - }, - "buyWithWyreDescription": { - "message": "최대 $ 1000 구매까지 간편한 온보딩. 신속한 대화형 상한 구매 확인. 직불/신용 카드, Apple Pay, 은행 송금 지원. 100여국 이상에서 사용 가능. MetaMask 계정으로 토큰 입금" - }, "bytes": { "message": "바이트" }, @@ -733,18 +704,6 @@ "continue": { "message": "계속" }, - "continueToCoinbasePay": { - "message": "Coinbase Pay로 계속하기" - }, - "continueToMoonPay": { - "message": "문페이로 계속하기" - }, - "continueToTransak": { - "message": "Transak으로 계속" - }, - "continueToWyre": { - "message": "Wyre로 넘어가기" - }, "contract": { "message": "계약" }, @@ -957,10 +916,6 @@ "deposit": { "message": "예치" }, - "depositCrypto": { - "message": "$1 입금", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "자세히 알아보기" }, @@ -973,12 +928,6 @@ "details": { "message": "세부 정보" }, - "directDepositCrypto": { - "message": "$1 직접 입금" - }, - "directDepositCryptoExplainer": { - "message": "이미 $1(이)가 있는 경우 직접 입금하는 것이 새 지갑에 $1(을)를 넣는 가장 빠른 방법입니다." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” 유형은 오리지널 가스비를 최소 10% 인상해야 하는 기준에 미치지 못하므로 비활성화되었습니다.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "일반" }, - "getEther": { - "message": "Ether 얻기" - }, - "getEtherFromFaucet": { - "message": "$1 네크워크 포시트에서 Ether 얻기", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "뒤로 가기" }, @@ -1928,10 +1870,6 @@ "message": "이 네트워크의 네이티브 토큰은 $1입니다. 이는 가스비 지불에 사용하는 토큰입니다.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "MetaMask로 디앱을 이용하려면 지갑에 $1(이)가 있어야 합니다.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "도움이 필요하신가요? $1에 문의하세요.", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "서비스 약관" }, - "testFaucet": { - "message": "수도꼭지(faucet) 테스트" - }, "testNetworks": { "message": "테스트 네트워크" }, @@ -4166,9 +4101,6 @@ "view": { "message": "보기" }, - "viewAccount": { - "message": "계정 보기" - }, "viewAllDetails": { "message": "모든 세부 정보 보기" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index c078c6fd4555..f703eb3b50ff 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Jūsų naršyklė neatpažįstama..." }, - "buyWithWyre": { - "message": "Pirkti $1 su „Wyre“" - }, - "buyWithWyreDescription": { - "message": "„Wyre“ leidžia naudotis kreditine kortele norint įnešti $1 tiesiai į jūsų „MetaMask“ paskyrą." - }, "bytes": { "message": "Baitai" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Jungiamasi prie pagrindinio „Ethereum“ tinklo" }, - "continueToWyre": { - "message": "Tęsti su „Wyre“" - }, "contractDeployment": { "message": "Sutarties išdėstymas" }, @@ -327,13 +318,6 @@ "general": { "message": "Bendra" }, - "getEther": { - "message": "Gauti eterių" - }, - "getEtherFromFaucet": { - "message": "Gaukite eterių iš čiaupo $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "„Goerli“ bandomasis tinklas" }, @@ -781,9 +765,6 @@ "terms": { "message": "Naudojimo sąlygos" }, - "testFaucet": { - "message": "Testuoti čiaupą" - }, "tips": { "message": "Arbatpinigiai" }, @@ -902,9 +883,6 @@ "userName": { "message": "Vartotojo vardas" }, - "viewAccount": { - "message": "Žiūrėti paskyrą" - }, "viewContact": { "message": "Peržiūrėti kontaktą" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index fe0c24411c97..46d4b0a7b8f9 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Jūsu pārlūkprogramma netiek atbalstīta..." }, - "buyWithWyre": { - "message": "Pirkt $1 ar Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre ļauj noguldīt $1 tieši jūsu MetaMask kontā, izmantojot kredītkarti." - }, "bytes": { "message": "Baiti" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Savienojas ar galveno Ethereum tīklu" }, - "continueToWyre": { - "message": "Pāriet uz Wyre" - }, "contractDeployment": { "message": "Līgumu pielietošana" }, @@ -323,13 +314,6 @@ "general": { "message": "Vispārīgi" }, - "getEther": { - "message": "Saņemt Ether" - }, - "getEtherFromFaucet": { - "message": "Vai vēlaties $1 iegūt Ether no krāna?", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli testa tīkls" }, @@ -777,9 +761,6 @@ "terms": { "message": "Lietošanas noteikumi" }, - "testFaucet": { - "message": "Testa krāns" - }, "tips": { "message": "Dzeramnauda" }, @@ -898,9 +879,6 @@ "userName": { "message": "Lietotājvārds" }, - "viewAccount": { - "message": "Skatīt kontu" - }, "viewContact": { "message": "Skatīt līgumu" }, diff --git a/app/_locales/ml/messages.json b/app/_locales/ml/messages.json index 5662cd9a4ac4..0ee00d08f7df 100644 --- a/app/_locales/ml/messages.json +++ b/app/_locales/ml/messages.json @@ -144,8 +144,5 @@ }, "userName": { "message": "ഉപയോക്തൃനാമം" - }, - "viewAccount": { - "message": "അക്കൗണ്ട് കാണുക" } } diff --git a/app/_locales/mr/messages.json b/app/_locales/mr/messages.json index 30729773dab8..5f19a27726df 100644 --- a/app/_locales/mr/messages.json +++ b/app/_locales/mr/messages.json @@ -144,8 +144,5 @@ }, "userName": { "message": "वापरकर्तानाव" - }, - "viewAccount": { - "message": "खाते पहा" } } diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index a223c311138a..fbc374dbbf21 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Pelayar anda tidak disokong..." }, - "buyWithWyre": { - "message": "Beli $1 dengan Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre membolehkan anda menggunakan kad kredit untuk mendeposit $1 secara terus ke dalam akaun MetaMask anda." - }, "bytes": { "message": "Bait" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Menyambung kepada Rangkaian Ethereum Utama" }, - "continueToWyre": { - "message": "Teruskan ke Wyre" - }, "contractDeployment": { "message": "Penyusunan Kontrak" }, @@ -320,13 +311,6 @@ "general": { "message": "Am" }, - "getEther": { - "message": "Dapatkan Ether" - }, - "getEtherFromFaucet": { - "message": "Dapatkan Ether daripada pili untuk $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Rangkaian Ujian Goerli" }, @@ -761,9 +745,6 @@ "terms": { "message": "Syarat-syarat Penggunaan" }, - "testFaucet": { - "message": "Uji Pili" - }, "tips": { "message": "Tip" }, @@ -879,9 +860,6 @@ "userName": { "message": "Nama pengguna" }, - "viewAccount": { - "message": "Paparkan Akaun" - }, "viewContact": { "message": "Lihat Kenalan" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index 46266da1c1ae..fc8a1e7fdfe0 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -119,13 +119,6 @@ "gasPrice": { "message": "Gasprijs (GWEI)" }, - "getEther": { - "message": "Krijg Ether" - }, - "getEtherFromFaucet": { - "message": "Haal Ether uit een kraan voor de $1", - "description": "Displays network name for Ether faucet" - }, "here": { "message": "hier", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -311,9 +304,6 @@ "terms": { "message": "Gebruiksvoorwaarden" }, - "testFaucet": { - "message": "Test de kraan" - }, "to": { "message": "Naar" }, @@ -345,9 +335,6 @@ "usedByClients": { "message": "Gebruikt door verschillende klanten" }, - "viewAccount": { - "message": "Bekijk account" - }, "visitWebSite": { "message": "Bezoek onze website" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 94c417469081..8f9639b6e7ee 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Nettleseren din støttes ikke ..." }, - "buyWithWyre": { - "message": "Kjøp $1 med Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre lar deg bruke et kredittkort for å sette inn $1 rett på MetaMask-kontoen din." - }, "cancel": { "message": "Avbryt" }, @@ -169,9 +163,6 @@ "connectingToMainnet": { "message": "Forbinder med hoved-Ethereumnettverk " }, - "continueToWyre": { - "message": "Fortsett til Wyre " - }, "contractDeployment": { "message": "Distribusjon av kontrakten" }, @@ -320,13 +311,6 @@ "general": { "message": "Generell" }, - "getEther": { - "message": "Skaff Ether " - }, - "getEtherFromFaucet": { - "message": "Få Ether fra en kran for $1", - "description": "Displays network name for Ether faucet" - }, "hardware": { "message": "Maskinvare" }, @@ -762,9 +746,6 @@ "terms": { "message": "Brukervilkår" }, - "testFaucet": { - "message": "Testkran" - }, "to": { "message": "Til " }, @@ -880,9 +861,6 @@ "userName": { "message": "Brukernavn" }, - "viewAccount": { - "message": "Se konto" - }, "viewContact": { "message": "Se kontrakt" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 6d55acc850a0..59e85e10487a 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -204,12 +204,6 @@ "buy": { "message": "Bumili" }, - "buyWithWyre": { - "message": "Bumili ng $1 gamit ang Wyre" - }, - "buyWithWyreDescription": { - "message": "Binibigyang-daan ka ng Wyre na gumamit ng debit card para mag-deposit ng $1 sa mismong MetaMask account mo." - }, "bytes": { "message": "Bytes" }, @@ -332,9 +326,6 @@ "continue": { "message": "Magpatuloy" }, - "continueToWyre": { - "message": "Magpatuloy sa Wyre" - }, "contract": { "message": "Kontrata" }, @@ -651,13 +642,6 @@ "general": { "message": "Pangkalahatan" }, - "getEther": { - "message": "Kunin ang Ether" - }, - "getEtherFromFaucet": { - "message": "Kunin ang Ether mula sa isang faucet sa halagang $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli Test Network" }, @@ -1754,9 +1738,6 @@ "termsOfService": { "message": "Mga Tuntunin ng Serbisyo" }, - "testFaucet": { - "message": "Test Faucet" - }, "tips": { "message": "Mga Tip" }, @@ -1917,9 +1898,6 @@ "message": "I-verify ang token na ito sa $1 at tiyaking ito ang token na gusto mong i-trade.", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, - "viewAccount": { - "message": "Tingnan ang Account" - }, "viewAllDetails": { "message": "Tingnan ang lahat ng detalye" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 6ce02742633e..aaf196fa7868 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Twoja przeglądarka nie jest obsługiwana..." }, - "buyWithWyre": { - "message": "Kup $1 poprzez Wyre" - }, - "buyWithWyreDescription": { - "message": "Dzięki Wyre możesz użyć karty kredytowej, aby wpłacić $1 bezpośrednio na swoje konto MetaMask." - }, "bytes": { "message": "Bajty" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Łączenie z główną siecią Ethereum" }, - "continueToWyre": { - "message": "Przejdź do Wyre" - }, "contractDeployment": { "message": "Uruchomienie kontraktu" }, @@ -327,13 +318,6 @@ "general": { "message": "Ogólne" }, - "getEther": { - "message": "Zdobądź Eter" - }, - "getEtherFromFaucet": { - "message": "Zdobądź Eter ze źródła za $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Sieć testowa Goerli" }, @@ -772,9 +756,6 @@ "terms": { "message": "Regulamin" }, - "testFaucet": { - "message": "Źródło testowego ETH" - }, "tips": { "message": "Napiwki" }, @@ -890,9 +871,6 @@ "userName": { "message": "Nazwa użytkownika" }, - "viewAccount": { - "message": "Zobacz konto" - }, "viewContact": { "message": "Wyświetl kontakt" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 0b40cef5f260..3373c150bb8a 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -523,38 +523,9 @@ "message": "Comprar $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Comprar $1 com o Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Você pode comprar ou transferir criptomoedas facilmente com sua conta na Coinbase.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Compre $1 com o MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "O MoonPay aceita formas de pagamento populares, incluindo Visa, Mastercard, Apple Pay, Google Pay, Samsung Pay e transferências bancárias em mais de 145 países. Os tokens são depositados na sua conta da MetaMask." - }, - "buyCryptoWithTransak": { - "message": "Comprar $1 com Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "O Transak aceita cartões de crédito, cartões de débito, Apple Pay, MobiKwik e transferências bancárias (dependendo da localização) em mais de 100 países. $1 deposita diretamente na sua conta da MetaMask.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Comprar agora" }, - "buyWithWyre": { - "message": "Comprar $1 com o Wyre" - }, - "buyWithWyreDescription": { - "message": "Integração fácil para compras de até US$ 1.000. Verificação de compra de alto limite rápida e interativa. Aceita cartão de crédito/débito, Apple Pay, transferências bancárias. Disponível em mais de 100 países. Depósito de tokens em sua conta na MetaMask" - }, "bytes": { "message": "Bytes" }, @@ -733,18 +704,6 @@ "continue": { "message": "Continuar" }, - "continueToCoinbasePay": { - "message": "Prosseguir para o Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Continuar para o MoonPay" - }, - "continueToTransak": { - "message": "Continuar para Transak" - }, - "continueToWyre": { - "message": "Continuar para o Wyre" - }, "contract": { "message": "Contrato" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Depositar" }, - "depositCrypto": { - "message": "Depositar $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Saiba mais" }, @@ -973,12 +928,6 @@ "details": { "message": "Detalhes" }, - "directDepositCrypto": { - "message": "Depositar $1 diretamente" - }, - "directDepositCryptoExplainer": { - "message": "Se já tiver alguns $1, a forma mais rápida de colocar $1 em sua nova carteira é por depósito direto." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” está desativado porque não satisfaz o aumento mínimo de 10% em relação à taxa de gás original.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Geral" }, - "getEther": { - "message": "Obter Ether" - }, - "getEtherFromFaucet": { - "message": "Receba Ether de um faucet para a rede $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Voltar" }, @@ -1928,10 +1870,6 @@ "message": "O token nativo dessa rede é $1. Esse é o token usado para taxas de gás.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Para interagir com aplicativos descentralizados usando a MetaMask, você precisará de $1 em sua carteira.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Precisa de ajuda? Contate $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Termos de Serviço" }, - "testFaucet": { - "message": "Faucet de teste" - }, "testNetworks": { "message": "Redes de teste" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Ver" }, - "viewAccount": { - "message": "Ver conta" - }, "viewAllDetails": { "message": "Ver todos os detalhes" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index d35b302c2d3d..a2a6580cc4f2 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -317,12 +317,6 @@ "buy": { "message": "Comprar" }, - "buyWithWyre": { - "message": "Comprar $1 com Wyre" - }, - "buyWithWyreDescription": { - "message": "Com o Wyre, você pode usar um cartão de débito para depositar $1 diretamente na sua conta da MetaMask." - }, "bytes": { "message": "Bytes" }, @@ -469,12 +463,6 @@ "continue": { "message": "Continuar" }, - "continueToTransak": { - "message": "Continuar para Transak" - }, - "continueToWyre": { - "message": "Continuar para o Wyre" - }, "contract": { "message": "Contrato" }, @@ -1030,13 +1018,6 @@ "general": { "message": "Geral" }, - "getEther": { - "message": "Obter Ether" - }, - "getEtherFromFaucet": { - "message": "Obtenha Ether de um faucet para $1", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Voltar" }, @@ -2604,9 +2585,6 @@ "termsOfService": { "message": "Termos de Serviço" }, - "testFaucet": { - "message": "Testar faucet" - }, "time": { "message": "Hora" }, @@ -2866,9 +2844,6 @@ "message": "Verifique esse token no $1 e confirme que é o token que você deseja negociar.", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, - "viewAccount": { - "message": "Ver conta" - }, "viewAllDetails": { "message": "Ver todos os detalhes" }, diff --git a/app/_locales/pt_PT/messages.json b/app/_locales/pt_PT/messages.json index d6faa33b4b19..ba2364c6f5df 100644 --- a/app/_locales/pt_PT/messages.json +++ b/app/_locales/pt_PT/messages.json @@ -158,9 +158,6 @@ "userName": { "message": "Nome de utilizador" }, - "viewAccount": { - "message": "Ver Conta" - }, "welcomeBack": { "message": "Bem-vindo de volta!" } diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 6d2a7055beb6..37e59a3456b8 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Browserul dvs. nu este compatibil..." }, - "buyWithWyre": { - "message": "Cumpărați $1 cu Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre vă permite să folosiți un card de credit pentru a depune $1 direct în contul dvs. MetaMask." - }, "bytes": { "message": "Octeți" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Se conectează la rețeaua Ethereum principală" }, - "continueToWyre": { - "message": "Continuați la Wyre" - }, "contractDeployment": { "message": "Implementarea contractului" }, @@ -320,13 +311,6 @@ "gasUsed": { "message": "Suma gaz folosită" }, - "getEther": { - "message": "Obțineți Ether" - }, - "getEtherFromFaucet": { - "message": "Obțineți Ether de la un robinet pentru $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Rețea de test Goerli" }, @@ -768,9 +752,6 @@ "terms": { "message": "Termeni și condiții" }, - "testFaucet": { - "message": "Robinet de testare" - }, "tips": { "message": "Cadouri bănești" }, @@ -883,9 +864,6 @@ "userName": { "message": "Nume utilizator" }, - "viewAccount": { - "message": "Afișați contul" - }, "viewContact": { "message": "Vizualizare contact" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 1874fc415a41..4cf9df874d96 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -523,38 +523,9 @@ "message": "Купить $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Купите $1 с помощью Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Вы можете легко купить или перевести криптовалюту с помощью своего счета Coinbase.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Купить $1 с помощью MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay поддерживает популярные способы оплаты, включая Visa, Mastercard, Apple/Google/Samsung Pay, а также банковские переводы в 145 странах. Токены зачисляются на ваш счет MetaMask." - }, - "buyCryptoWithTransak": { - "message": "Купить $1 с помощью Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak поддерживает кредитные и дебетовые карты, Apple Pay, MobiKwik и банковские переводы (в зависимости от местоположения) в более чем 100 странах. $1 вносится прямо на ваш счет MetaMask.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Купить сейчас" }, - "buyWithWyre": { - "message": "Купить 1 $ с помощью Wyre" - }, - "buyWithWyreDescription": { - "message": "Простая регистрация для покупок на сумму до 1000 $. Быстрая интерактивная проверка покупки с высоким лимитом. Поддерживает дебетовые/кредитные карты, Apple Pay, банковские переводы. Доступно в более чем 100 странах. Токены зачисляются на ваш счет MetaMask" - }, "bytes": { "message": "Байты" }, @@ -733,18 +704,6 @@ "continue": { "message": "Продолжить" }, - "continueToCoinbasePay": { - "message": "Перейти на Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Перейти в MoonPay" - }, - "continueToTransak": { - "message": "Перейти в Transak" - }, - "continueToWyre": { - "message": "Перейти к Wyre" - }, "contract": { "message": "Контракт" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Внести деньги" }, - "depositCrypto": { - "message": "Внесите $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Подробнее" }, @@ -973,12 +928,6 @@ "details": { "message": "Подробности" }, - "directDepositCrypto": { - "message": "Внесите $1 напрямую" - }, - "directDepositCryptoExplainer": { - "message": "Если у вас уже есть немного $1, самый быстрый способ получить $1 в новый кошелек — это прямой депозит." - }, "disabledGasOptionToolTipMessage": { "message": "$1 отключена, поскольку не соответствует минимальному увеличению на 10% от первоначальной платы за газ.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Общее" }, - "getEther": { - "message": "Получить Ether" - }, - "getEtherFromFaucet": { - "message": "Получите из крана Ether для сети $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Назад" }, @@ -1928,10 +1870,6 @@ "message": "Нативный токен этой сети — $1. Этот токен используется для оплаты газа.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Для взаимодействия с децентрализованными приложениями с помощью MetaMask вам понадобится $1 в вашем кошельке.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Нужна помощь? Обратитесь в $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Условия обслуживания" }, - "testFaucet": { - "message": "Тестовый кран" - }, "testNetworks": { "message": "Протестировать сети" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Просмотр" }, - "viewAccount": { - "message": "Смотреть счет" - }, "viewAllDetails": { "message": "Смотреть все сведения" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 447cc23df1ae..b98b4022f943 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -118,12 +118,6 @@ "browserNotSupported": { "message": "Váš prehliadač nie je podporovaný..." }, - "buyWithWyre": { - "message": "Kúpte $1 s Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre vám umožňuje použiť kreditnú kartu na vloženie depozitu $1 priamo na váš účet MetaMask." - }, "bytes": { "message": "Bajty" }, @@ -166,9 +160,6 @@ "connectingToMainnet": { "message": "Připojuji se k Ethereum Mainnet" }, - "continueToWyre": { - "message": "Pokračovať na Wyre" - }, "contractDeployment": { "message": "Nasazení kontraktu" }, @@ -321,13 +312,6 @@ "general": { "message": "Všeobecne" }, - "getEther": { - "message": "Získejte Ether" - }, - "getEtherFromFaucet": { - "message": "Získejte Ether z faucetu za $1.", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Testovacia sieť Goerli" }, @@ -750,9 +734,6 @@ "terms": { "message": "Podmínky použití" }, - "testFaucet": { - "message": "Testovací faucet" - }, "tips": { "message": "Príspevky" }, @@ -868,9 +849,6 @@ "userName": { "message": "Meno používateľa" }, - "viewAccount": { - "message": "Zobrazit účet" - }, "viewContact": { "message": "Zobraziť kontakt" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index d5c4c23f9548..247fc2eb3a8a 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Vaš brskalnik ni podptrt ..." }, - "buyWithWyre": { - "message": "Kupi $1 z Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre vam omogoča, da s kreditno kartico nakažete $1 neposredno na svoj račun MetaMask." - }, "bytes": { "message": "Bajti" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "Povezovanje na glavno omrežje" }, - "continueToWyre": { - "message": "Nadaljuj na Wyre" - }, "contractDeployment": { "message": "Ustvarjanje pogodbe" }, @@ -324,13 +315,6 @@ "general": { "message": "Splošno" }, - "getEther": { - "message": "Pridobi Ether" - }, - "getEtherFromFaucet": { - "message": "Pridobite Ether iz fauceta za $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Testno omrežje Goerli" }, @@ -769,9 +753,6 @@ "terms": { "message": "Pogoji uporabe" }, - "testFaucet": { - "message": "Testni faucet" - }, "tips": { "message": "Nasveti" }, @@ -890,9 +871,6 @@ "userName": { "message": "Uporabniško ime" }, - "viewAccount": { - "message": "Poglej račun" - }, "viewContact": { "message": "Ogled stika" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 824c77e2ca28..875be6323bce 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Vaš pregledač nije podržan..." }, - "buyWithWyre": { - "message": "Kupite $1 preko servisa Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre vam dozvoljava da koristite kreditnu karticu kako biste deponovali $1 pravo na vaš MetaMask nalog." - }, "bytes": { "message": "Bajtovi" }, @@ -169,9 +163,6 @@ "connectingToMainnet": { "message": "Povezuje se na glavnu Ethereum mrežu" }, - "continueToWyre": { - "message": "Nastavite ka Wyre" - }, "contractDeployment": { "message": "Primena ugovora" }, @@ -324,13 +315,6 @@ "general": { "message": "Opšte" }, - "getEther": { - "message": "Nabavite Ether" - }, - "getEtherFromFaucet": { - "message": "Preuzmite Ether sa slavine za $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Test mreža Goerli " }, @@ -887,9 +871,6 @@ "userName": { "message": "Корисничко име" }, - "viewAccount": { - "message": "Прикажи налог" - }, "viewContact": { "message": "Pogledaj kontakt" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index dbacb38d4573..2b4eb8734cb1 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Din webbläsare stöds inte..." }, - "buyWithWyre": { - "message": "Köp $1 med Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre låter dig använda ett kreditkort för att sätta in $1 direkt på ditt MetaMask-konto." - }, "cancel": { "message": "Avbryt" }, @@ -166,9 +160,6 @@ "connectingToMainnet": { "message": "Koppla till Ethereums huvudnätverk" }, - "continueToWyre": { - "message": "Fortsätt till Wyre" - }, "contractDeployment": { "message": "Kontraktplacering" }, @@ -317,13 +308,6 @@ "general": { "message": "Allmänt" }, - "getEther": { - "message": "Skaffa Ether" - }, - "getEtherFromFaucet": { - "message": "Få Ether från en kran för $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Goerli testnätverk" }, @@ -762,9 +746,6 @@ "terms": { "message": "Användarvillkor" }, - "testFaucet": { - "message": "Test-faucet" - }, "tips": { "message": "Donationer" }, @@ -877,9 +858,6 @@ "userName": { "message": "Användarnamn" }, - "viewAccount": { - "message": "Visa konto" - }, "viewContact": { "message": "Visa kontakt" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 1377cae31b14..161b59ee6d20 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -121,12 +121,6 @@ "browserNotSupported": { "message": "Kivinjari chaku hakiwezeshwi..." }, - "buyWithWyre": { - "message": "Nunua $1 kwa kutumia Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre inakuwezesha kutumia kadi ya benki kuweka $1 moja kwa moja kwenye akaunti yako ya MetaMask." - }, "cancel": { "message": "Ghairi" }, @@ -166,9 +160,6 @@ "connectingToMainnet": { "message": "Inaunganisha kwenye Mtandao Mkuu wa Ethereum" }, - "continueToWyre": { - "message": "Endelea kwenye Wyre" - }, "contractDeployment": { "message": "Kutoa Mkataba" }, @@ -317,13 +308,6 @@ "general": { "message": "Jumla" }, - "getEther": { - "message": "Pata Ether" - }, - "getEtherFromFaucet": { - "message": "Pata Ether kutoka kwenye mfereji $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Mtandao wa Majaribio wa Goerli" }, @@ -759,9 +743,6 @@ "terms": { "message": "Masharti ya Matumizi" }, - "testFaucet": { - "message": "Mfereji wa Jaribio" - }, "tips": { "message": "Michango" }, @@ -880,9 +861,6 @@ "userName": { "message": "Jina la mtumiaji" }, - "viewAccount": { - "message": "Angalia Akaunti" - }, "viewContact": { "message": "Tazama Mawasiliano" }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index f6772badbb2c..53b5a906ede2 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -167,13 +167,6 @@ "gasPrice": { "message": "எரிவாயு விலை (GWEI)" }, - "getEther": { - "message": "ஈத்தர் கிடைக்கும்" - }, - "getEtherFromFaucet": { - "message": "$ 1 க்கு ஒரு குழாய் இருந்து ஈதர் கிடைக்கும்$1", - "description": "Displays network name for Ether faucet" - }, "here": { "message": "இங்கே", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -426,9 +419,6 @@ "terms": { "message": "பயன்பாட்டு விதிமுறைகளை" }, - "testFaucet": { - "message": "சோதனை குழாய்" - }, "to": { "message": "பெறுநர்" }, @@ -475,9 +465,6 @@ "userName": { "message": "பயனர்பெயர்" }, - "viewAccount": { - "message": "கணக்கைப் பார்" - }, "visitWebSite": { "message": "எங்கள் வலைத்தளத்தைப் பார்வையிடவும்" }, diff --git a/app/_locales/te/messages.json b/app/_locales/te/messages.json index 6f1f3831de5e..dee823b90423 100644 --- a/app/_locales/te/messages.json +++ b/app/_locales/te/messages.json @@ -144,8 +144,5 @@ }, "userName": { "message": "యూజర్‌పేరు" - }, - "viewAccount": { - "message": "ఖాతాను వీక్షించండి" } } diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index 37d721407c16..42b71a318fd0 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -72,9 +72,6 @@ "connectingToMainnet": { "message": "เชื่อมต่อกับเครือข่าย Ethereum หลัก" }, - "continueToWyre": { - "message": "ไปที่ Wyre" - }, "contractDeployment": { "message": "การติดตั้งสัญญา" }, @@ -164,13 +161,6 @@ "general": { "message": "ทั่วไป" }, - "getEther": { - "message": "รับอีเธอร์" - }, - "getEtherFromFaucet": { - "message": "รับอีเธอร์ที่ปล่อยจาก $1", - "description": "Displays network name for Ether faucet" - }, "here": { "message": "ที่นี่", "description": "as in -click here- for more information (goes with troubleTokenBalances)" @@ -396,9 +386,6 @@ "terms": { "message": "ข้อตกลงในการใช้งาน" }, - "testFaucet": { - "message": "ตัวแจกจ่ายเพื่อการทดสอบ" - }, "to": { "message": "ถึง" }, @@ -445,9 +432,6 @@ "usedByClients": { "message": "ถูกใช้งานโดยหลายไคลเอนท์" }, - "viewAccount": { - "message": "ดูบัญชี" - }, "visitWebSite": { "message": "เยี่ยมชมเว็บไซต์ของเรา" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 5aab2fe6e16d..b342de9789f7 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -523,38 +523,9 @@ "message": "Bumili ng $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Bumili ng $1 gamit ang Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Madali kang makakabili o makakapagtransfer ng crypto gamit ang iyong Coinbase account.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Bumili ng $1 gamit ang MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "Suportado ng MoonPay ang mga kilalang paraan ng pagbabayad, kabilang ang Visa, Mastercard, Apple / Google / Samsung Pay, at mga bank transfer sa higit 145 na bansa. Ang mga token ay madedeposito sa iyong MetaMask account." - }, - "buyCryptoWithTransak": { - "message": "Bumili ng $1 gamit ang Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Suportado ng Transak ang mga credit at debit card, Apple Pay, MobiKwik, at mga bank transfer (depende sa lokasyon) sa higit 100 bansa. Ang $1 ay direktang madedeposito sa iyong MetaMask account.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Bilhin Ngayon" }, - "buyWithWyre": { - "message": "Bumili ng $1 gamit ang Wyre" - }, - "buyWithWyreDescription": { - "message": "Madaling onboarding para sa mga pagbili hanggang $ 1000. Mabilis na interactive na high limit na pag-verify ng pagbili. Sinusuportahan ang Debit/Credit Card, Apple Pay, Bank Transfers. Available sa 100+ na mga bansa. Deposito ng mga token sa iyong MetaMask Account" - }, "bytes": { "message": "Bytes" }, @@ -733,18 +704,6 @@ "continue": { "message": "Magpatuloy" }, - "continueToCoinbasePay": { - "message": "Magpatuloy sa Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Magpatuloy sa MoonPay" - }, - "continueToTransak": { - "message": "Magpatuloy sa Transak" - }, - "continueToWyre": { - "message": "Magpatuloy sa Wyre" - }, "contract": { "message": "Kontrata" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Deposito" }, - "depositCrypto": { - "message": "Magdeposito ng $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Matuto pa" }, @@ -973,12 +928,6 @@ "details": { "message": "Mga Detalye" }, - "directDepositCrypto": { - "message": "Direktang Magdeposito ng $1" - }, - "directDepositCryptoExplainer": { - "message": "Kung mayroon ka ng $1, ang pinakamabilis na paraan upang mailagay ang $1 sa iyong bagong wallet ay sa direktang pag-deposit." - }, "disabledGasOptionToolTipMessage": { "message": "Ang “$1” ay naka-disable dahil hindi nito naabot ang minimum na 10% na dagdag mula sa orihinal na singil sa gas.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Pangkalahatan" }, - "getEther": { - "message": "Kunin ang Ether" - }, - "getEtherFromFaucet": { - "message": "Kunin ang Ether mula sa isang faucet para sa network na $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Bumalik" }, @@ -1928,10 +1870,6 @@ "message": "Ang native token sa network na ito ay $1. Ito ang token na ginagamit para sa mga gas fee.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Para makipag-ugnayan sa mga desentralisadong applicaiton gamit ang MetaMask, kakailanganin mo ng $1 sa iyong wallet.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Kailangan ng tulong? Makipag-ugnayan sa $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Mga Tuntunin ng Serbisyo" }, - "testFaucet": { - "message": "Test Faucet" - }, "testNetworks": { "message": "Suriin ang mga network" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Tingnan" }, - "viewAccount": { - "message": "Tingnan ang Account" - }, "viewAllDetails": { "message": "Tingnan ang lahat ng detalye" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 180558fc6ade..1d4d6194d439 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -523,38 +523,9 @@ "message": "$1 satın al", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Coinbase Pay ile 1 USD al", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Coinbase hesabınla kolayca kripto para satın alabilir veya transfer edebilirsin.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "MoonPay ile $1 satın al", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay, Visa, Mastercard, Apple / Google / Samsung Pay dahil olmak üzere popüler ödeme yöntemlerini ve 145'ten fazla ülkede banka havalelerini destekler. Token'lar MetaMask hesabına yatırılır." - }, - "buyCryptoWithTransak": { - "message": "Transak ile $1 satın al", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak, 100'den fazla ülkede kredi ve banka kartlarını, Apple Pay, MobiKwik ve banka transferlerini (konuma bağlı olarak) destekler. $1 doğrudan MetaMask hesabına yatırılır.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Şimdi Satın Al" }, - "buyWithWyre": { - "message": "Wyre ile $1 satın al" - }, - "buyWithWyreDescription": { - "message": "1000$'a kadar satın alma işlemlerinde kolay oryantasyon. Banka Kartı/Kredi Kartı, Apple Pay, Banka Transferlerini destekler. +100 ülkede kullanılabilir. Token'lar MetaMask Hesabına yatırılır" - }, "bytes": { "message": "Bayt" }, @@ -733,18 +704,6 @@ "continue": { "message": "Devam et" }, - "continueToCoinbasePay": { - "message": "Coinbase Pay'e devam et" - }, - "continueToMoonPay": { - "message": "MoonPay'e devam et" - }, - "continueToTransak": { - "message": "Transak'a Devam Et" - }, - "continueToWyre": { - "message": "Wyre'a Devam Et" - }, "contract": { "message": "Sözleşme" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Para Yatır" }, - "depositCrypto": { - "message": "$1 yatır", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Daha fazla bilgi edinin" }, @@ -973,12 +928,6 @@ "details": { "message": "Ayrıntılar" }, - "directDepositCrypto": { - "message": "Doğrudan $1 Yatır" - }, - "directDepositCryptoExplainer": { - "message": "Halihazırda $1 sahibiysen yeni cüzdanına doğrudan para yatırma yoluyla $1 almanın en hızlı yolu." - }, "disabledGasOptionToolTipMessage": { "message": "Orijinal gas ücretinden minimum %10'luk bir artışı karşılamadığı için \"$1\" devre dışı bırakıldı.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Genel" }, - "getEther": { - "message": "Ether Al" - }, - "getEtherFromFaucet": { - "message": "Musluktan $1 karşılığı Ether al", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Geri git" }, @@ -1928,10 +1870,6 @@ "message": "Bu ağdaki yerli token $1. Bu gaz ücretleri için kullanılan tokendir.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "MetaMask kullanarak merkezi olmayan uygulamalarla etkileşim kurmak için cüzdanında $1 bulunmasına ihtiyacın olacak.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Yardıma mı ihtiyacınız var? $1 bölümüne ulaşın", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Hizmet şartları" }, - "testFaucet": { - "message": "Test musluğu" - }, "testNetworks": { "message": "Test ağları" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Görüntüle" }, - "viewAccount": { - "message": "Hesabı görüntüle" - }, "viewAllDetails": { "message": "Tüm bilgileri görüntüle" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index d3c716ff22d2..6609fec2f0f1 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -124,12 +124,6 @@ "browserNotSupported": { "message": "Ваш браузер не підтримується..." }, - "buyWithWyre": { - "message": "Купити $1 через Wyre" - }, - "buyWithWyreDescription": { - "message": "Wyre дає змогу використовувати кредитну картку для внесення валюти $1 безпосередньо у свій гаманець MetaMask." - }, "bytes": { "message": "Байти" }, @@ -172,9 +166,6 @@ "connectingToMainnet": { "message": "З'єднуємось з Головною мережею Ethereum" }, - "continueToWyre": { - "message": "Продовжити у Wyre" - }, "contractDeployment": { "message": "Розгортання контракту" }, @@ -327,13 +318,6 @@ "general": { "message": "Загальні" }, - "getEther": { - "message": "Отримати Ефір" - }, - "getEtherFromFaucet": { - "message": "Отримайте Ether з крану за $1", - "description": "Displays network name for Ether faucet" - }, "goerli": { "message": "Тестова мережа Goerli " }, @@ -781,9 +765,6 @@ "terms": { "message": "Умови використання" }, - "testFaucet": { - "message": "Тестовий кран" - }, "tips": { "message": "Чайові" }, @@ -902,9 +883,6 @@ "userName": { "message": "Ім’я користувача" }, - "viewAccount": { - "message": "Переглянути обліковий запис" - }, "viewContact": { "message": "Переглянути контакт" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 17e6d233101c..bd8ff7efb8a3 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -523,38 +523,9 @@ "message": "Mua $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "Mua $1 bằng Coinbase Pay", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "Bạn có thể dễ dàng mua hoặc chuyển khoản tiền điện tử bằng tài khoản Coinbase của mình.", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "Mua $1 bằng MoonPay", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay hỗ trợ các phương thức thanh toán phổ biến, bao gồm Visa, Mastercard, Apple / Google / Samsung Pay và chuyển khoản ngân hàng tại hơn 145 quốc gia. Nạp token vào tài khoản MetaMask của bạn." - }, - "buyCryptoWithTransak": { - "message": "Mua $1 bằng Transak", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak hỗ trợ thẻ tín dụng và ghi nợ, Apple Pay, MobiKwik và chuyển khoản ngân hàng (tùy thuộc vào vị trí) tại hơn 100 quốc gia. Nạp trực tiếp $1 vào tài khoản MetaMask của bạn.", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "Mua ngay" }, - "buyWithWyre": { - "message": "Mua $1 qua Wyre" - }, - "buyWithWyreDescription": { - "message": "Dễ dàng tham gia đối với các giao dịch mua lên đến $1.000. Xác minh mua hàng giới hạn cao và tương tác nhanh. Hỗ trợ Thẻ Tín dụng/Ghi nợ, Apple Pay, Chuyển khoản Ngân hàng. Hiện có tại hơn 100 quốc gia. Nạp token vào Tài khoản MetaMask của bạn" - }, "bytes": { "message": "Byte" }, @@ -733,18 +704,6 @@ "continue": { "message": "Tiếp tục" }, - "continueToCoinbasePay": { - "message": "Tiếp tục đến Coinbase Pay" - }, - "continueToMoonPay": { - "message": "Tiếp tục đến MoonPay" - }, - "continueToTransak": { - "message": "Tiếp tục đến Transak" - }, - "continueToWyre": { - "message": "Tiếp tục chuyển đến Wyre" - }, "contract": { "message": "Hợp đồng" }, @@ -957,10 +916,6 @@ "deposit": { "message": "Nạp" }, - "depositCrypto": { - "message": "Nạp $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "Tìm hiểu thêm" }, @@ -973,12 +928,6 @@ "details": { "message": "Chi tiết" }, - "directDepositCrypto": { - "message": "Nạp trực tiếp $1" - }, - "directDepositCryptoExplainer": { - "message": "Nếu bạn đã có một ít $1, nạp trực tiếp là cách nhanh nhất để nhận $1 trong ví mới." - }, "disabledGasOptionToolTipMessage": { "message": "“$1” bị vô hiệu hóa vì không đạt mức tăng tối thiểu 10% so với phí gas ban đầu.", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "Chung" }, - "getEther": { - "message": "Nhận Ether" - }, - "getEtherFromFaucet": { - "message": "Nhận Ether từ một vòi dành cho mạng $1.", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Quay Lại" }, @@ -1928,10 +1870,6 @@ "message": "Token gốc của mạng này là $1. Token này được dùng làm phí gas.", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "Để tương tác với các ứng dụng phi tập trung bằng MetaMask, bạn sẽ cần $1 trong ví.", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "Bạn cần trợ giúp? Liên hệ $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "Điều khoản dịch vụ" }, - "testFaucet": { - "message": "Vòi thử nghiệm" - }, "testNetworks": { "message": "Mạng thử nghiệm" }, @@ -4166,9 +4101,6 @@ "view": { "message": "Xem" }, - "viewAccount": { - "message": "Xem tài khoản" - }, "viewAllDetails": { "message": "Xem toàn bộ chi tiết" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index cf7a16cd7923..af66b9fd872b 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -523,38 +523,9 @@ "message": "购买$1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyCryptoWithCoinbasePay": { - "message": "用Coinbase Pay购买$1", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithCoinbasePayDescription": { - "message": "您可以使用Coinbase账户轻松购买或转移加密货币。", - "description": "$1 represents the crypto symbol to be purchased" - }, - "buyCryptoWithMoonPay": { - "message": "用MoonPay购买$1", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithMoonPayDescription": { - "message": "MoonPay支持热门的支付方式,包括Visa、万事达卡、Apple / Google / Samsung Pay,以及超过145个国家/地区的银行转账。代币会被存入您的MetaMask账户。" - }, - "buyCryptoWithTransak": { - "message": "用Transak购买$1", - "description": "$1 represents the cypto symbol to be purchased" - }, - "buyCryptoWithTransakDescription": { - "message": "Transak在超过100个国家/地区支持信用卡和借记卡、Apple Pay、MobiKwik和银行转账(取决于地点)。$1会被直接存入您的MetaMask账户。", - "description": "$1 represents the crypto symbol to be purchased" - }, "buyNow": { "message": "立即购买" }, - "buyWithWyre": { - "message": "使用Wyre购买$1" - }, - "buyWithWyreDescription": { - "message": "购买不超过$1000可以轻松开通。快速交互式上限购买验证。支持借记卡/信用卡、Apple Pay、银行转账。适用于100多个国家。代币存入您的MetaMask账户" - }, "bytes": { "message": "字节" }, @@ -733,18 +704,6 @@ "continue": { "message": "继续" }, - "continueToCoinbasePay": { - "message": "继续使用Coinbase Pay" - }, - "continueToMoonPay": { - "message": "继续使用MoonPay" - }, - "continueToTransak": { - "message": "继续前往 Transak" - }, - "continueToWyre": { - "message": "继续前往 Wyre" - }, "contract": { "message": "合约" }, @@ -957,10 +916,6 @@ "deposit": { "message": "存入" }, - "depositCrypto": { - "message": "存入$1", - "description": "$1 represents the crypto symbol to be purchased" - }, "deprecatedTestNetworksLink": { "message": "了解详情" }, @@ -973,12 +928,6 @@ "details": { "message": "详细信息" }, - "directDepositCrypto": { - "message": "直接存入$1" - }, - "directDepositCryptoExplainer": { - "message": "如果您已经有了一些$1,那么在您的新钱包里获得$1的最快方式是直接存入。" - }, "disabledGasOptionToolTipMessage": { "message": "“$1”已被禁用,因为它不满足在原来的燃料费用基础上至少增加10%的要求。", "description": "$1 is gas estimate type which can be market or aggressive" @@ -1432,13 +1381,6 @@ "general": { "message": "常规" }, - "getEther": { - "message": "获取以太币" - }, - "getEtherFromFaucet": { - "message": "从 $1 网络的水龙头获取以太币", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "返回" }, @@ -1928,10 +1870,6 @@ "message": "此网络上的原生代币为$1。它是用于燃料费的代币。", "description": "$1 represents the name of the native token on the current network" }, - "needCryptoInWallet": { - "message": "要使用MetaMask与去中心化应用程序互动,您的钱包中需要有$1。", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "需要帮助?请联系 $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -3809,9 +3747,6 @@ "termsOfService": { "message": "服务条款" }, - "testFaucet": { - "message": "测试水龙头" - }, "testNetworks": { "message": "测试网络" }, @@ -4166,9 +4101,6 @@ "view": { "message": "查看" }, - "viewAccount": { - "message": "查看账户" - }, "viewAllDetails": { "message": "查看所有详情" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index badb17ff3f08..6fb45813b863 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -200,12 +200,6 @@ "buy": { "message": "買" }, - "buyWithWyre": { - "message": "用 Wyre 購買 $1" - }, - "buyWithWyreDescription": { - "message": "Wyre 讓你使用信用卡在 MetaMask 帳戶中直接存入 $1 。" - }, "bytes": { "message": "位元組" }, @@ -334,9 +328,6 @@ "continue": { "message": "繼續" }, - "continueToWyre": { - "message": "繼續前往 Wyre" - }, "contractAddressError": { "message": "您正在將代幣傳送到代幣合約的位址。這可能會導致這些代幣遺失。" }, @@ -435,19 +426,9 @@ "deleteNetworkDescription": { "message": "你確定要刪除網路嗎?" }, - "depositCrypto": { - "message": "存入 $1", - "description": "$1 represents the crypto symbol to be purchased" - }, "details": { "message": "詳情" }, - "directDepositCrypto": { - "message": "直接存入 $1" - }, - "directDepositCryptoExplainer": { - "message": "如果您已經擁有一些 $1,直接存入功能是讓新錢包最快取得的方式。" - }, "disconnect": { "message": "中斷連結" }, @@ -669,13 +650,6 @@ "general": { "message": "一般" }, - "getEther": { - "message": "取得以太幣" - }, - "getEtherFromFaucet": { - "message": "從水龍頭取得 $1 上的以太幣", - "description": "Displays network name for Ether faucet" - }, "goBack": { "message": "Go Back" }, @@ -899,10 +873,6 @@ "name": { "message": "名稱" }, - "needCryptoInWallet": { - "message": "要使用 MetaMask 存取去中心化應用程式時,您的錢包中需要有 $1。", - "description": "$1 represents the cypto symbol to be purchased" - }, "needHelp": { "message": "需要幫助?聯繫$1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -1444,9 +1414,6 @@ "termsOfService": { "message": "服務條款" }, - "testFaucet": { - "message": "測試水龍頭" - }, "tips": { "message": "提示" }, @@ -1606,9 +1573,6 @@ "message": "在 $1 驗證這個代幣的資訊", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, - "viewAccount": { - "message": "查看帳戶" - }, "viewAllDetails": { "message": "查看所有詳情" }, diff --git a/app/scripts/lib/buy-url.test.js b/app/scripts/lib/buy-url.test.js deleted file mode 100644 index 80b8d41163e4..000000000000 --- a/app/scripts/lib/buy-url.test.js +++ /dev/null @@ -1,109 +0,0 @@ -import nock from 'nock'; -import { - BUYABLE_CHAINS_MAP, - CHAIN_IDS, - CURRENCY_SYMBOLS, -} from '../../../shared/constants/network'; -import { TRANSAK_API_KEY, MOONPAY_API_KEY } from '../constants/on-ramp'; -import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps'; -import getBuyUrl from './buy-url'; - -const WYRE_ACCOUNT_ID = 'AC-7AG3W4XH4N2'; -const ETH_ADDRESS = '0x0dcd5d886577d5581b0c524242ef2ee70be3e7bc'; -const MAINNET = { - chainId: CHAIN_IDS.MAINNET, - amount: 5, - address: ETH_ADDRESS, -}; -const BSC = { - chainId: CHAIN_IDS.BSC, - amount: 5, - address: ETH_ADDRESS, -}; -const POLYGON = { - chainId: CHAIN_IDS.POLYGON, - amount: 5, - address: ETH_ADDRESS, -}; - -describe('buy-url', () => { - it('returns Wyre url with an ETH address for Ethereum mainnet', async () => { - nock(SWAPS_API_V2_BASE_URL) - .get( - `/networks/1/fiatOnRampUrl?serviceName=wyre&destinationAddress=${ETH_ADDRESS}¤cy=${CURRENCY_SYMBOLS.ETH}`, - ) - .reply(200, { - url: `https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=${CURRENCY_SYMBOLS.ETH}&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`, - }); - const wyreUrl = await getBuyUrl(MAINNET); - expect(wyreUrl).toStrictEqual( - `https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=${CURRENCY_SYMBOLS.ETH}&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`, - ); - nock.cleanAll(); - }); - - it('returns a fallback Wyre url if /orders/reserve API call fails', async () => { - const wyreUrl = await getBuyUrl(MAINNET); - - expect(wyreUrl).toStrictEqual( - `https://pay.sendwyre.com/purchase?dest=ethereum:${ETH_ADDRESS}&destCurrency=${CURRENCY_SYMBOLS.ETH}&accountId=${WYRE_ACCOUNT_ID}&paymentMethod=debit-card`, - ); - }); - - it('returns Transak url with an ETH address for Ethereum mainnet', async () => { - const transakUrl = await getBuyUrl({ ...MAINNET, service: 'transak' }); - const buyableChain = BUYABLE_CHAINS_MAP[MAINNET.chainId]; - - expect(transakUrl).toStrictEqual( - `https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&defaultCryptoCurrency=${buyableChain.transakCurrencies[0]}&networks=${buyableChain.network}&walletAddress=${ETH_ADDRESS}`, - ); - }); - - it('returns Transak url with an BNB address for Binance Smart Chain', async () => { - const transakUrl = await getBuyUrl({ ...BSC, service: 'transak' }); - const buyableChain = BUYABLE_CHAINS_MAP[BSC.chainId]; - - expect(transakUrl).toStrictEqual( - `https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&defaultCryptoCurrency=${buyableChain.transakCurrencies[0]}&networks=${buyableChain.network}&walletAddress=${ETH_ADDRESS}`, - ); - }); - - it('returns Transak url with an MATIC address for Polygon', async () => { - const transakUrl = await getBuyUrl({ ...POLYGON, service: 'transak' }); - const buyableChain = BUYABLE_CHAINS_MAP[POLYGON.chainId]; - - expect(transakUrl).toStrictEqual( - `https://global.transak.com/?apiKey=${TRANSAK_API_KEY}&hostURL=https%3A%2F%2Fmetamask.io&defaultCryptoCurrency=${buyableChain.transakCurrencies[0]}&networks=${buyableChain.network}&walletAddress=${ETH_ADDRESS}`, - ); - }); - - it('returns a MoonPay url with a prefilled wallet address for the Ethereum network', async () => { - const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} } = - BUYABLE_CHAINS_MAP[MAINNET.chainId]; - const moonPayQueryParams = new URLSearchParams({ - apiKey: MOONPAY_API_KEY, - walletAddress: MAINNET.address, - defaultCurrencyCode, - showOnlyCurrencies, - }); - const queryParams = new URLSearchParams({ - url: `https://buy.moonpay.com?${moonPayQueryParams}`, - context: 'extension', - }); - nock(SWAPS_API_V2_BASE_URL) - .get(`/moonpaySign/?${queryParams}`) - .reply(200, { - url: `https://buy.moonpay.com/?apiKey=${MOONPAY_API_KEY}&walletAddress=${MAINNET.address}&defaultCurrencyCode=${defaultCurrencyCode}&showOnlyCurrencies=${showOnlyCurrencies}&signature=laefTlgkESEc2hv8AZEH9F25VjLEJUADY27D6MccE54%3D`, - }); - const moonPayUrl = await getBuyUrl({ ...MAINNET, service: 'moonpay' }); - expect(moonPayUrl).toStrictEqual( - `https://buy.moonpay.com/?apiKey=${MOONPAY_API_KEY}&walletAddress=${MAINNET.address}&defaultCurrencyCode=${defaultCurrencyCode}&showOnlyCurrencies=${showOnlyCurrencies}&signature=laefTlgkESEc2hv8AZEH9F25VjLEJUADY27D6MccE54%3D`, - ); - nock.cleanAll(); - }); - - it('returns an empty string if generating a MoonPay url fails', async () => { - const moonPayUrl = await getBuyUrl({ ...MAINNET, service: 'moonpay' }); - expect(moonPayUrl).toStrictEqual(''); - }); -}); diff --git a/app/scripts/lib/buy-url.ts b/app/scripts/lib/buy-url.ts deleted file mode 100644 index 30c2b4613b6d..000000000000 --- a/app/scripts/lib/buy-url.ts +++ /dev/null @@ -1,245 +0,0 @@ -import log from 'loglevel'; - -import { isNullOrUndefined } from '@metamask/utils'; -import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps'; -import { - BUYABLE_CHAINS_MAP, - CHAIN_IDS, - WyreChainSettings, - CurrencySymbol, - ChainId, -} from '../../../shared/constants/network'; -import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'; -import { - TRANSAK_API_KEY, - MOONPAY_API_KEY, - COINBASEPAY_API_KEY, -} from '../constants/on-ramp'; -import { formatMoonpaySymbol } from '../../../ui/helpers/utils/moonpay'; - -const fetchWithTimeout = getFetchWithTimeout(); - -/** - * Create a Wyre purchase URL. - * - * @param walletAddress - Ethereum destination address - * @param chainId - Current chain ID - * @param symbol - Token symbol to buy - * @returns String - */ -const createWyrePurchaseUrl = async ( - walletAddress: string, - chainId: keyof typeof BUYABLE_CHAINS_MAP, - symbol?: CurrencySymbol, -): Promise => { - const { wyre = {} as WyreChainSettings } = BUYABLE_CHAINS_MAP[chainId]; - const { srn, currencyCode } = wyre; - - const networkId = parseInt(chainId, 16); - const fiatOnRampUrlApi = `${SWAPS_API_V2_BASE_URL}/networks/${networkId}/fiatOnRampUrl?serviceName=wyre&destinationAddress=${walletAddress}¤cy=${ - symbol || currencyCode - }`; - const wyrePurchaseUrlFallback = `https://pay.sendwyre.com/purchase?dest=${srn}:${walletAddress}&destCurrency=${ - symbol || currencyCode - }&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`; - try { - const response = await fetchWithTimeout(fiatOnRampUrlApi, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const parsedResponse = await response.json(); - if (response.ok && parsedResponse.url) { - return parsedResponse.url; - } - log.warn('Failed to create a Wyre purchase URL', parsedResponse); - } catch (err) { - log.warn('Failed to create a Wyre purchase URL', err); - } - return wyrePurchaseUrlFallback; // In case the API call would fail, we return a fallback URL for Wyre's Checkout. -}; - -/** - * Create a Transak Checkout URL. - * API docs here: https://www.notion.so/Query-Parameters-9ec523df3b874ec58cef4fa3a906f238 - * - * @param walletAddress - Ethereum destination address - * @param chainId - Current chain ID - * @param symbol - Token symbol to buy - * @returns String - */ -const createTransakUrl = ( - walletAddress: string, - chainId: keyof typeof BUYABLE_CHAINS_MAP, - symbol?: CurrencySymbol, -): string => { - const { nativeCurrency, network } = BUYABLE_CHAINS_MAP[chainId]; - - const queryParams = new URLSearchParams({ - apiKey: TRANSAK_API_KEY, - hostURL: 'https://metamask.io', - defaultCryptoCurrency: symbol || nativeCurrency, - networks: network, - walletAddress, - }); - - return `https://global.transak.com/?${queryParams}`; -}; - -/** - * Create a MoonPay Checkout URL. - * - * @param walletAddress - Destination address - * @param chainId - Current chain ID - * @param symbol - Token symbol to buy - * @returns String - */ -const createMoonPayUrl = async ( - walletAddress: string, - chainId: keyof typeof BUYABLE_CHAINS_MAP, - symbol?: CurrencySymbol, -): Promise => { - const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} as any } = - BUYABLE_CHAINS_MAP[chainId]; - const moonPayQueryParams = new URLSearchParams({ - apiKey: MOONPAY_API_KEY, - walletAddress, - defaultCurrencyCode: symbol - ? formatMoonpaySymbol(symbol, chainId) - : defaultCurrencyCode, - showOnlyCurrencies, - }); - const queryParams = new URLSearchParams({ - url: `https://buy.moonpay.com?${moonPayQueryParams}`, - context: 'extension', - }); - const moonPaySignUrl = `${SWAPS_API_V2_BASE_URL}/moonpaySign/?${queryParams}`; - try { - const response = await fetchWithTimeout(moonPaySignUrl, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const parsedResponse = await response.json(); - if (response.ok && parsedResponse.url) { - return parsedResponse.url; - } - log.warn('Failed to create a MoonPay purchase URL', parsedResponse); - } catch (err) { - log.warn('Failed to create a MoonPay purchase URL', err); - } - return ''; -}; - -/** - * Create a Coinbase Pay Checkout URL. - * - * @param walletAddress - Ethereum destination address - * @param chainId - Current chain ID - * @param symbol - Token symbol to buy - * @returns String - */ -const createCoinbasePayUrl = ( - walletAddress: string, - chainId: keyof typeof BUYABLE_CHAINS_MAP, - symbol?: CurrencySymbol, -): string => { - // since coinbasePayCurrencies is going to be extended to include all tokens supported - // we now default to nativeCurrency instead of the 2 previous tokens + eth that we had before - const { nativeCurrency } = BUYABLE_CHAINS_MAP[chainId]; - const queryParams = new URLSearchParams({ - appId: COINBASEPAY_API_KEY, - attribution: 'extension', - destinationWallets: JSON.stringify([ - { - address: walletAddress, - assets: symbol ? [symbol] : [nativeCurrency], - }, - ]), - }); - return `https://pay.coinbase.com/buy?${queryParams}`; -}; - -/** - * Gives the caller a url at which the user can acquire eth, depending on the network they are in - * - * @param opts - Options required to determine the correct url - * @param opts.chainId - The chainId for which to return a url - * @param opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'. - * @param opts.service - * @param opts.symbol - The symbol of the token to buy. Only relevant if buying a token. - * @returns The url at which the user can access ETH, while in the given chain. If the passed - * chainId does not match any of the specified cases, or if no chainId is given, returns undefined. - */ -export default async function getBuyUrl({ - chainId, - address, - service, - symbol, -}: { - chainId: keyof typeof BUYABLE_CHAINS_MAP; - address?: string; - service?: string; - symbol?: CurrencySymbol; -}): Promise { - let serviceToUse = service; - // default service by network if not specified - if (isNullOrUndefined(service)) { - // eslint-disable-next-line no-param-reassign - serviceToUse = getDefaultServiceForChain(chainId); - } - - switch (serviceToUse) { - case 'wyre': - if (address) { - return await createWyrePurchaseUrl(address as string, chainId, symbol); - } - throw new Error('Address is required when requesting url for Wyre'); - case 'transak': - if (address) { - return createTransakUrl(address as string, chainId, symbol); - } - throw new Error('Address is required when requesting url for Transak'); - case 'moonpay': - if (address) { - return createMoonPayUrl(address as string, chainId, symbol); - } - throw new Error('Address is required when requesting url for Moonpay'); - case 'coinbase': - if (address) { - return createCoinbasePayUrl(address as string, chainId, symbol); - } - throw new Error( - 'Address is required when requesting url for Coinbase Pay', - ); - case 'metamask-faucet': - return 'https://faucet.metamask.io/'; - case 'goerli-faucet': - return 'https://goerli-faucet.slock.it/'; - case 'sepolia-faucet': - return 'https://faucet.sepolia.dev/'; - default: - throw new Error( - `Unknown cryptocurrency exchange or faucet: "${service}"`, - ); - } -} - -function getDefaultServiceForChain(chainId: ChainId): string { - switch (chainId) { - case CHAIN_IDS.MAINNET: - return 'wyre'; - case CHAIN_IDS.GOERLI: - return 'goerli-faucet'; - case CHAIN_IDS.SEPOLIA: - return 'sepolia-faucet'; - default: - throw new Error( - `No default cryptocurrency exchange or faucet for chainId: "${chainId}"`, - ); - } -} diff --git a/development/ts-migration-dashboard/files-to-convert.json b/development/ts-migration-dashboard/files-to-convert.json index 1a509ecabd94..254019f80dab 100644 --- a/development/ts-migration-dashboard/files-to-convert.json +++ b/development/ts-migration-dashboard/files-to-convert.json @@ -68,8 +68,6 @@ "app/scripts/lib/ComposableObservableStore.js", "app/scripts/lib/ComposableObservableStore.test.js", "app/scripts/lib/account-tracker.js", - "app/scripts/lib/buy-url.js", - "app/scripts/lib/buy-url.test.js", "app/scripts/lib/cleanErrorStack.js", "app/scripts/lib/cleanErrorStack.test.js", "app/scripts/lib/createLoggerMiddleware.js", @@ -456,9 +454,6 @@ "ui/components/app/currency-input/currency-input.stories.js", "ui/components/app/currency-input/currency-input.test.js", "ui/components/app/currency-input/index.js", - "ui/components/app/deposit-popover/on-ramp-item.js", - "ui/components/app/deposit-popover/deposit-popover.js", - "ui/components/app/deposit-popover/index.js", "ui/components/app/detected-token/detected-token-address/detected-token-address.js", "ui/components/app/detected-token/detected-token-address/detected-token-address.stories.js", "ui/components/app/detected-token/detected-token-address/detected-token-address.test.js", @@ -920,16 +915,10 @@ "ui/components/ui/loading-indicator/loading-indicator.js", "ui/components/ui/loading-screen/index.js", "ui/components/ui/loading-screen/loading-screen.component.js", - "ui/components/ui/logo/logo-coinbasepay.js", - "ui/components/ui/logo/logo-deposit-eth.js", "ui/components/ui/logo/logo-lattice.js", "ui/components/ui/logo/logo-ledger.js", - "ui/components/ui/logo/logo-moonpay.js", - "ui/components/ui/logo/logo-moonpay.test.js", "ui/components/ui/logo/logo-qr-based.js", - "ui/components/ui/logo/logo-transak.js", "ui/components/ui/logo/logo-trezor.js", - "ui/components/ui/logo/logo-wyre.js", "ui/components/ui/logo/logo.stories.js", "ui/components/ui/mascot/index.js", "ui/components/ui/mascot/mascot.component.js", diff --git a/package.json b/package.json index 89eaab77d744..8f6d5652bd3d 100644 --- a/package.json +++ b/package.json @@ -414,6 +414,7 @@ "@types/pump": "^1.1.1", "@types/react": "^16.9.53", "@types/react-dom": "^17.0.11", + "@types/react-redux": "^7.1.25", "@types/remote-redux-devtools": "^0.5.5", "@types/w3c-web-hid": "^1.0.3", "@types/watchify": "^3.11.1", diff --git a/shared/constants/network.ts b/shared/constants/network.ts index 3fd5e4b338cc..7f08046856ff 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -19,11 +19,6 @@ export type ChainId = typeof CHAIN_IDS[keyof typeof CHAIN_IDS]; */ export type CurrencySymbol = typeof CURRENCY_SYMBOLS[keyof typeof CURRENCY_SYMBOLS]; -/** - * A type that is a union type for the supported symbols on different onramp providers. - */ -type SupportedCurrencySymbol = - typeof SUPPORTED_CURRENCY_SYMBOLS[keyof typeof SUPPORTED_CURRENCY_SYMBOLS]; /** * Test networks have special symbols that combine the network name and 'ETH' * so that they are distinct from mainnet and other networks that use 'ETH'. @@ -31,36 +26,6 @@ type SupportedCurrencySymbol = export type TestNetworkCurrencySymbol = typeof TEST_NETWORK_TICKER_MAP[keyof typeof TEST_NETWORK_TICKER_MAP]; -/** - * MoonPay is a fiat onramp provider, and there are some special strings that - * inform the MoonPay API which network the user is attempting to onramp into. - * This type reflects those possible values. - */ -type MoonPayNetworkAbbreviation = 'BSC' | 'CCHAIN' | 'POLYGON'; - -/** - * MoonPay requires some settings that are configured per network that it is - * enabled on. This type describes those settings. - */ -export type MoonPayChainSettings = { - /** - * What should the default onramp currency be, for example 'eth' on 'mainnet' - * This type matches a single SupportedCurrencySymbol or a - * SupportedCurrencySymbol and a MoonPayNetworkAbbreviation joined by a '_'. - */ - defaultCurrencyCode: - | SupportedCurrencySymbol - | `${SupportedCurrencySymbol}_${MoonPayNetworkAbbreviation}`; - /** - * We must also configure all possible onramp currencies we wish to support. - * This type matches either an array of SupportedCurrencySymbol or - * an array of SupportedCurrencySymbol and a MoonPayNetworkAbbreviation joined by a '_'. - */ - showOnlyCurrencies: - | SupportedCurrencySymbol[] - | `${SupportedCurrencySymbol}_${MoonPayNetworkAbbreviation}`[]; -}; - /** * An object containing preferences for an RPC definition */ @@ -101,25 +66,6 @@ export type RPCDefinition = { rpcPrefs: RPCPreferences; }; -/** - * Wyre is a fiat onramp provider. We must provide some settings for networks - * that support Wyre. - */ -export type WyreChainSettings = { - /** - * The network name - */ - srn: string; - /** - * The native currency for the network - */ - currencyCode: CurrencySymbol; - /** - * The list of supported currencies for the Wyre onramp provider - */ - currencies: SupportedCurrencySymbol[]; -}; - /** * For each chain that we support fiat onramps for, we provide a set of * configuration options that help for initializing the connectiong to the @@ -134,22 +80,6 @@ type BuyableChainSettings = { * The network name or identifier */ network: string; - /** - * The list of supported currencies for the Transak onramp provider - */ - transakCurrencies?: SupportedCurrencySymbol[]; - /** - * A configuration object for the MoonPay onramp provider - */ - moonPay?: MoonPayChainSettings; - /** - * A configuration object for the Wyre onramp provider - */ - wyre?: WyreChainSettings; - /** - * The list of supported currencies for the CoinbasePay onramp provider - */ - coinbasePayCurrencies?: SupportedCurrencySymbol[]; }; /** @@ -286,133 +216,6 @@ export const CURRENCY_SYMBOLS = { OPTIMISM: 'OP', } as const; -/** - * An object containing the token symbols for various tokens that are supported - * on different on ramp providers. This object is meant for internal consumption, - * hence why it is not exported. - */ -const SUPPORTED_CURRENCY_SYMBOLS = { - ...CURRENCY_SYMBOLS, - '1INCH': '1INCH', - AAVE: 'AAVE', - ABT: 'ABT', - ACH: 'ACH', - AGEUR: 'AGEUR', - AGLD: 'AGLD', - AMP: 'AMP', - ANKR: 'ANKR', - APE: 'APE', - ARPA: 'ARPA', - ASM: 'ASM', - AUCTION: 'AUCTION', - AXS: 'AXS', - AVAX: 'AVAX', - AVAXC: 'AVAXC', - AVAXCUSDC: 'AVAXCUSDC', - BADGER: 'BADGER', - BAL: 'BAL', - BAND: 'BAND', - BAT: 'BAT', - BNT: 'BNT', - BOBA: 'BOBA', - BOND: 'BOND', - BTRST: 'BTRST', - CHAIN: 'CHAIN', - CHZ: 'CHZ', - CLV: 'CLV', - COMP: 'COMP', - COTI: 'COTI', - CRO: 'CRO', - CRV: 'CRV', - CTSI: 'CTSI', - CVC: 'CVC', - DAO: 'DAO', - DDX: 'DDX', - DNT: 'DNT', - ENJ: 'ENJ', - ENS: 'ENS', - EURT: 'EURT', - FARM: 'FARM', - FET: 'FET', - FORTH: 'FORTH', - FX: 'FX', - GNO: 'GNO', - GRT: 'GRT', - GTC: 'GTC', - GTH: 'GTH', - GUSD: 'GUSD', - GYEN: 'GYEN', - HEX: 'HEX', - IOTX: 'IOTX', - IMX: 'IMX', - JASMY: 'JASMY', - KEEP: 'KEEP', - KNC: 'KNC', - KRL: 'KRL', - LCX: 'LCX', - LINK: 'LINK', - LPT: 'LPT', - LRC: 'LRC', - MANA: 'MANA', - MASK: 'MASK', - MINDS: 'MINDS', - MIR: 'MIR', - MKR: 'MKR', - MLN: 'MLN', - MTL: 'MTL', - MUSDC: 'mUSDC', - NKN: 'NKN', - NMR: 'NMR', - NU: 'NU', - OGN: 'OGN', - OMG: 'OMG', - ORN: 'ORN', - OXT: 'OXT', - PAX: 'PAX', - PERP: 'PERP', - PLA: 'PLA', - POLS: 'POLS', - POLY: 'POLY', - QNT: 'QNT', - QUICK: 'QUICK', - RAD: 'RAD', - RAI: 'RAI', - RARI: 'RARI', - REN: 'REN', - REP: 'REP', - REQ: 'REQ', - RLC: 'RLC', - RLY: 'RLY', - SAND: 'SAND', - SHIB: 'SHIB', - SKL: 'SKL', - SNX: 'SNX', - SPA: 'SPA', - STETH: 'STETH', - STORJ: 'STORJ', - SUKU: 'SUKU', - SUSHI: 'SUSHI', - SWAP: 'SWAP', - SWFTC: 'SWFTC', - TRAC: 'TRAC', - TRB: 'TRB', - TRIBE: 'TRIBE', - TRU: 'TRU', - TXL: 'TXL', - UMA: 'UMA', - UNI: 'UNI', - USDS: 'USDS', - VRA: 'VRA', - WBTC: 'WBTC', - WCFG: 'WCFG', - XYO: 'XYO', - YFII: 'YFII', - YFI: 'YFI', - YLD: 'YLD', - ZRX: 'ZRX', - ZUSD: 'ZUSD', -} as const; - export const ETH_TOKEN_IMAGE_URL = './images/eth_logo.svg'; export const TEST_ETH_TOKEN_IMAGE_URL = './images/black-eth-logo.svg'; export const BNB_TOKEN_IMAGE_URL = './images/bnb.png'; @@ -697,188 +500,12 @@ export const BUYABLE_CHAINS_MAP: { | typeof CHAIN_IDS.MOONBEAM | typeof CHAIN_IDS.MOONBEAM_TESTNET | typeof CHAIN_IDS.MOONRIVER + | typeof CHAIN_IDS.AURORA >]: BuyableChainSettings; } = { [CHAIN_IDS.MAINNET]: { nativeCurrency: CURRENCY_SYMBOLS.ETH, network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME, - transakCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.ETH, - SUPPORTED_CURRENCY_SYMBOLS['1INCH'], - SUPPORTED_CURRENCY_SYMBOLS.AAVE, - SUPPORTED_CURRENCY_SYMBOLS.AGEUR, - SUPPORTED_CURRENCY_SYMBOLS.BUSD, - SUPPORTED_CURRENCY_SYMBOLS.CHAIN, - SUPPORTED_CURRENCY_SYMBOLS.CLV, - SUPPORTED_CURRENCY_SYMBOLS.COMP, - SUPPORTED_CURRENCY_SYMBOLS.CTSI, - SUPPORTED_CURRENCY_SYMBOLS.DAI, - SUPPORTED_CURRENCY_SYMBOLS.DAO, - SUPPORTED_CURRENCY_SYMBOLS.ENJ, - SUPPORTED_CURRENCY_SYMBOLS.EURT, - SUPPORTED_CURRENCY_SYMBOLS.GTH, - SUPPORTED_CURRENCY_SYMBOLS.HEX, - SUPPORTED_CURRENCY_SYMBOLS.LINK, - SUPPORTED_CURRENCY_SYMBOLS.MANA, - SUPPORTED_CURRENCY_SYMBOLS.MASK, - SUPPORTED_CURRENCY_SYMBOLS.MINDS, - SUPPORTED_CURRENCY_SYMBOLS.MKR, - SUPPORTED_CURRENCY_SYMBOLS.PLA, - SUPPORTED_CURRENCY_SYMBOLS.POLS, - SUPPORTED_CURRENCY_SYMBOLS.SAND, - SUPPORTED_CURRENCY_SYMBOLS.STETH, - SUPPORTED_CURRENCY_SYMBOLS.SUSHI, - SUPPORTED_CURRENCY_SYMBOLS.SWAP, - SUPPORTED_CURRENCY_SYMBOLS.TXL, - SUPPORTED_CURRENCY_SYMBOLS.UNI, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - SUPPORTED_CURRENCY_SYMBOLS.USDT, - SUPPORTED_CURRENCY_SYMBOLS.VRA, - SUPPORTED_CURRENCY_SYMBOLS.WBTC, - SUPPORTED_CURRENCY_SYMBOLS.YLD, - ], - moonPay: { - defaultCurrencyCode: SUPPORTED_CURRENCY_SYMBOLS.ETH, - showOnlyCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.ETH, - SUPPORTED_CURRENCY_SYMBOLS.USDT, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - SUPPORTED_CURRENCY_SYMBOLS.DAI, - SUPPORTED_CURRENCY_SYMBOLS.MATIC, - SUPPORTED_CURRENCY_SYMBOLS.ORN, - SUPPORTED_CURRENCY_SYMBOLS.WETH, - SUPPORTED_CURRENCY_SYMBOLS.IMX, - ], - }, - wyre: { - srn: 'ethereum', - currencyCode: CURRENCY_SYMBOLS.ETH, - currencies: [ - SUPPORTED_CURRENCY_SYMBOLS.ETH, - SUPPORTED_CURRENCY_SYMBOLS.AAVE, - SUPPORTED_CURRENCY_SYMBOLS.BAT, - SUPPORTED_CURRENCY_SYMBOLS.BUSD, - SUPPORTED_CURRENCY_SYMBOLS.COMP, - SUPPORTED_CURRENCY_SYMBOLS.CRV, - SUPPORTED_CURRENCY_SYMBOLS.DAI, - SUPPORTED_CURRENCY_SYMBOLS.GUSD, - SUPPORTED_CURRENCY_SYMBOLS.GYEN, - SUPPORTED_CURRENCY_SYMBOLS.LINK, - SUPPORTED_CURRENCY_SYMBOLS.MKR, - SUPPORTED_CURRENCY_SYMBOLS.PAX, - SUPPORTED_CURRENCY_SYMBOLS.RAI, - SUPPORTED_CURRENCY_SYMBOLS.SNX, - SUPPORTED_CURRENCY_SYMBOLS.UMA, - SUPPORTED_CURRENCY_SYMBOLS.UNI, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - SUPPORTED_CURRENCY_SYMBOLS.USDS, - SUPPORTED_CURRENCY_SYMBOLS.USDT, - SUPPORTED_CURRENCY_SYMBOLS.WBTC, - SUPPORTED_CURRENCY_SYMBOLS.WETH, - SUPPORTED_CURRENCY_SYMBOLS.YFI, - SUPPORTED_CURRENCY_SYMBOLS.ZUSD, - ], - }, - coinbasePayCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.ETH, - SUPPORTED_CURRENCY_SYMBOLS['1INCH'], - SUPPORTED_CURRENCY_SYMBOLS.AAVE, - SUPPORTED_CURRENCY_SYMBOLS.ABT, - SUPPORTED_CURRENCY_SYMBOLS.ACH, - SUPPORTED_CURRENCY_SYMBOLS.AGLD, - SUPPORTED_CURRENCY_SYMBOLS.AMP, - SUPPORTED_CURRENCY_SYMBOLS.ANKR, - SUPPORTED_CURRENCY_SYMBOLS.APE, - SUPPORTED_CURRENCY_SYMBOLS.ARPA, - SUPPORTED_CURRENCY_SYMBOLS.ASM, - SUPPORTED_CURRENCY_SYMBOLS.AUCTION, - SUPPORTED_CURRENCY_SYMBOLS.AXS, - SUPPORTED_CURRENCY_SYMBOLS.BADGER, - SUPPORTED_CURRENCY_SYMBOLS.BAL, - SUPPORTED_CURRENCY_SYMBOLS.BAND, - SUPPORTED_CURRENCY_SYMBOLS.BAT, - SUPPORTED_CURRENCY_SYMBOLS.BNT, - SUPPORTED_CURRENCY_SYMBOLS.BOBA, - SUPPORTED_CURRENCY_SYMBOLS.BOND, - SUPPORTED_CURRENCY_SYMBOLS.BTRST, - SUPPORTED_CURRENCY_SYMBOLS.CHZ, - SUPPORTED_CURRENCY_SYMBOLS.CLV, - SUPPORTED_CURRENCY_SYMBOLS.COMP, - SUPPORTED_CURRENCY_SYMBOLS.COTI, - SUPPORTED_CURRENCY_SYMBOLS.CRO, - SUPPORTED_CURRENCY_SYMBOLS.CRV, - SUPPORTED_CURRENCY_SYMBOLS.CTSI, - SUPPORTED_CURRENCY_SYMBOLS.CVC, - SUPPORTED_CURRENCY_SYMBOLS.DAI, - SUPPORTED_CURRENCY_SYMBOLS.DDX, - SUPPORTED_CURRENCY_SYMBOLS.DNT, - SUPPORTED_CURRENCY_SYMBOLS.ENJ, - SUPPORTED_CURRENCY_SYMBOLS.ENS, - SUPPORTED_CURRENCY_SYMBOLS.FARM, - SUPPORTED_CURRENCY_SYMBOLS.FET, - SUPPORTED_CURRENCY_SYMBOLS.FORTH, - SUPPORTED_CURRENCY_SYMBOLS.FX, - SUPPORTED_CURRENCY_SYMBOLS.GNO, - SUPPORTED_CURRENCY_SYMBOLS.GRT, - SUPPORTED_CURRENCY_SYMBOLS.GTC, - SUPPORTED_CURRENCY_SYMBOLS.IOTX, - SUPPORTED_CURRENCY_SYMBOLS.JASMY, - SUPPORTED_CURRENCY_SYMBOLS.KEEP, - SUPPORTED_CURRENCY_SYMBOLS.KNC, - SUPPORTED_CURRENCY_SYMBOLS.KRL, - SUPPORTED_CURRENCY_SYMBOLS.LCX, - SUPPORTED_CURRENCY_SYMBOLS.LINK, - SUPPORTED_CURRENCY_SYMBOLS.LPT, - SUPPORTED_CURRENCY_SYMBOLS.LRC, - SUPPORTED_CURRENCY_SYMBOLS.MANA, - SUPPORTED_CURRENCY_SYMBOLS.MASK, - SUPPORTED_CURRENCY_SYMBOLS.MATIC, - SUPPORTED_CURRENCY_SYMBOLS.MIR, - SUPPORTED_CURRENCY_SYMBOLS.MKR, - SUPPORTED_CURRENCY_SYMBOLS.MLN, - SUPPORTED_CURRENCY_SYMBOLS.MTL, - SUPPORTED_CURRENCY_SYMBOLS.NKN, - SUPPORTED_CURRENCY_SYMBOLS.NMR, - SUPPORTED_CURRENCY_SYMBOLS.NU, - SUPPORTED_CURRENCY_SYMBOLS.OGN, - SUPPORTED_CURRENCY_SYMBOLS.OMG, - SUPPORTED_CURRENCY_SYMBOLS.OXT, - SUPPORTED_CURRENCY_SYMBOLS.PAX, - SUPPORTED_CURRENCY_SYMBOLS.PERP, - SUPPORTED_CURRENCY_SYMBOLS.PLA, - SUPPORTED_CURRENCY_SYMBOLS.POLY, - SUPPORTED_CURRENCY_SYMBOLS.QNT, - SUPPORTED_CURRENCY_SYMBOLS.QUICK, - SUPPORTED_CURRENCY_SYMBOLS.RAD, - SUPPORTED_CURRENCY_SYMBOLS.RAI, - SUPPORTED_CURRENCY_SYMBOLS.RARI, - SUPPORTED_CURRENCY_SYMBOLS.REN, - SUPPORTED_CURRENCY_SYMBOLS.REP, - SUPPORTED_CURRENCY_SYMBOLS.REQ, - SUPPORTED_CURRENCY_SYMBOLS.RLC, - SUPPORTED_CURRENCY_SYMBOLS.RLY, - SUPPORTED_CURRENCY_SYMBOLS.SAND, - SUPPORTED_CURRENCY_SYMBOLS.SHIB, - SUPPORTED_CURRENCY_SYMBOLS.SKL, - SUPPORTED_CURRENCY_SYMBOLS.SNX, - SUPPORTED_CURRENCY_SYMBOLS.STORJ, - SUPPORTED_CURRENCY_SYMBOLS.SUKU, - SUPPORTED_CURRENCY_SYMBOLS.SUSHI, - SUPPORTED_CURRENCY_SYMBOLS.SWFTC, - SUPPORTED_CURRENCY_SYMBOLS.TRAC, - SUPPORTED_CURRENCY_SYMBOLS.TRB, - SUPPORTED_CURRENCY_SYMBOLS.TRIBE, - SUPPORTED_CURRENCY_SYMBOLS.TRU, - SUPPORTED_CURRENCY_SYMBOLS.UMA, - SUPPORTED_CURRENCY_SYMBOLS.UNI, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - SUPPORTED_CURRENCY_SYMBOLS.USDT, - SUPPORTED_CURRENCY_SYMBOLS.WBTC, - SUPPORTED_CURRENCY_SYMBOLS.WCFG, - SUPPORTED_CURRENCY_SYMBOLS.XYO, - SUPPORTED_CURRENCY_SYMBOLS.YFII, - SUPPORTED_CURRENCY_SYMBOLS.ZRX, - ], }, [CHAIN_IDS.GOERLI]: { nativeCurrency: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.GOERLI], @@ -891,98 +518,30 @@ export const BUYABLE_CHAINS_MAP: { [CHAIN_IDS.BSC]: { nativeCurrency: CURRENCY_SYMBOLS.BNB, network: 'bsc', - transakCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.BNB, - SUPPORTED_CURRENCY_SYMBOLS.BUSD, - ], - moonPay: { - defaultCurrencyCode: `${SUPPORTED_CURRENCY_SYMBOLS.BNB}_BSC`, - showOnlyCurrencies: [ - `${SUPPORTED_CURRENCY_SYMBOLS.BNB}_BSC`, - `${SUPPORTED_CURRENCY_SYMBOLS.BUSD}_BSC`, - ], - }, }, [CHAIN_IDS.POLYGON]: { nativeCurrency: CURRENCY_SYMBOLS.MATIC, network: 'polygon', - transakCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.MATIC, - SUPPORTED_CURRENCY_SYMBOLS.USDT, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - SUPPORTED_CURRENCY_SYMBOLS.DAI, - ], - moonPay: { - defaultCurrencyCode: `${SUPPORTED_CURRENCY_SYMBOLS.BNB}_POLYGON`, - showOnlyCurrencies: [ - `${SUPPORTED_CURRENCY_SYMBOLS.MATIC}_POLYGON`, - `${SUPPORTED_CURRENCY_SYMBOLS.USDC}_POLYGON`, - ], - }, - wyre: { - srn: 'matic', - currencyCode: CURRENCY_SYMBOLS.MATIC, - currencies: [ - SUPPORTED_CURRENCY_SYMBOLS.MATIC, - SUPPORTED_CURRENCY_SYMBOLS.MUSDC, - ], - }, }, [CHAIN_IDS.AVALANCHE]: { nativeCurrency: CURRENCY_SYMBOLS.AVALANCHE, network: 'avaxcchain', - transakCurrencies: [SUPPORTED_CURRENCY_SYMBOLS.AVALANCHE], - moonPay: { - defaultCurrencyCode: `${SUPPORTED_CURRENCY_SYMBOLS.AVAX}_CCHAIN`, - showOnlyCurrencies: [`${SUPPORTED_CURRENCY_SYMBOLS.AVAX}_CCHAIN`], - }, - wyre: { - srn: 'avalanche', - currencyCode: CURRENCY_SYMBOLS.AVALANCHE, - currencies: [ - SUPPORTED_CURRENCY_SYMBOLS.AVALANCHE, - SUPPORTED_CURRENCY_SYMBOLS.AVAXC, - SUPPORTED_CURRENCY_SYMBOLS.AVAXCUSDC, - ], - }, - coinbasePayCurrencies: [SUPPORTED_CURRENCY_SYMBOLS.AVALANCHE], }, [CHAIN_IDS.FANTOM]: { nativeCurrency: CURRENCY_SYMBOLS.FANTOM, network: 'fantom', - transakCurrencies: [SUPPORTED_CURRENCY_SYMBOLS.FANTOM], }, [CHAIN_IDS.CELO]: { nativeCurrency: CURRENCY_SYMBOLS.CELO, network: 'celo', - transakCurrencies: [SUPPORTED_CURRENCY_SYMBOLS.CELO], - moonPay: { - defaultCurrencyCode: SUPPORTED_CURRENCY_SYMBOLS.CELO, - showOnlyCurrencies: [SUPPORTED_CURRENCY_SYMBOLS.CELO], - }, }, [CHAIN_IDS.OPTIMISM]: { nativeCurrency: CURRENCY_SYMBOLS.ETH, network: 'optimism', - transakCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.ETH, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - ], }, [CHAIN_IDS.ARBITRUM]: { nativeCurrency: CURRENCY_SYMBOLS.ARBITRUM, network: 'arbitrum', - transakCurrencies: [ - SUPPORTED_CURRENCY_SYMBOLS.ARBITRUM, - SUPPORTED_CURRENCY_SYMBOLS.SPA, - SUPPORTED_CURRENCY_SYMBOLS.USDC, - SUPPORTED_CURRENCY_SYMBOLS.USDS, - ], - }, - [CHAIN_IDS.AURORA]: { - nativeCurrency: CURRENCY_SYMBOLS.AURORA, - network: 'aurora', - transakCurrencies: [SUPPORTED_CURRENCY_SYMBOLS.AURORA], }, }; diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index fded9dd8326c..7dea635f3a39 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -25,7 +25,6 @@ @import 'connected-status-indicator/index'; @import 'create-new-vault/create-new-vault.scss'; @import 'custom-spending-cap/index'; -@import 'deposit-popover/index'; @import 'edit-gas-display/index'; @import 'edit-gas-fee-button/index'; @import 'edit-gas-fee-popover/index'; diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index 05f8ff32d87b..9ac822f5930d 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -9,7 +9,6 @@ import ErrorMessage from '../../../ui/error-message'; import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../../helpers/constants/error-keys'; import Typography from '../../../ui/typography'; import { TypographyVariant } from '../../../../helpers/constants/design-system'; -import DepositPopover from '../../deposit-popover/deposit-popover'; import SecurityProviderBannerMessage from '../../security-provider-banner-message/security-provider-banner-message'; import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../../security-provider-banner-message/security-provider-banner-message.constants'; @@ -60,10 +59,6 @@ export default class ConfirmPageContainerContent extends Component { txData: PropTypes.object, }; - state = { - setShowDepositPopover: false, - }; - renderContent() { const { detailsComponent, dataComponent } = this.props; @@ -179,8 +174,6 @@ export default class ConfirmPageContainerContent extends Component { (errorKey || errorMessage) && errorKey === INSUFFICIENT_FUNDS_ERROR_KEY; - const { setShowDepositPopover } = this.state; - return (
- this.setState({ setShowDepositPopover: true }) - } + onClick={() => { + const portfolioUrl = process.env.PORTFOLIO_URL; + global.platform.openTab({ + url: `${portfolioUrl}/buy?metamaskEntry=ext_buy_button`, + }); + }} key={`${nativeCurrency}-buy-button`} > {t('buyAsset', [nativeCurrency])} @@ -261,11 +257,6 @@ export default class ConfirmPageContainerContent extends Component { />
)} - {setShowDepositPopover && ( - this.setState({ setShowDepositPopover: false })} - /> - )} { } = props; const t = useI18nContext(); + const trackEvent = useContext(MetaMetricsContext); - const [showDepositPopover, setShowDepositPopover] = useState(false); const [collectionBalance, setCollectionBalance] = useState(0); const isBuyableChain = useSelector(getIsBuyableChain); @@ -109,6 +111,12 @@ const ConfirmPageContainer = (props) => { getMetadataContractName(state, toAddress), ); + // TODO: Move useRamps hook to the confirm-transaction-base parent component. + // TODO: openBuyCryptoInPdapp should be passed to this component as a custom prop. + // We try to keep this component for layout purpose only, we need to move this hook to the confirm-transaction-base parent + // component once it is converted to a functional component + const { openBuyCryptoInPdapp } = useRamps(); + const isSetApproveForAll = currentTransaction.type === TransactionType.tokenMethodSetApprovalForAll; @@ -236,7 +244,17 @@ const ConfirmPageContainer = (props) => {
)} - {showDepositPopover && ( - setShowDepositPopover(false)} /> - )} {shouldDisplayWarning && errorKey !== INSUFFICIENT_FUNDS_ERROR_KEY && (
diff --git a/ui/components/app/deposit-popover/deposit-popover.js b/ui/components/app/deposit-popover/deposit-popover.js deleted file mode 100644 index b0128a5f179e..000000000000 --- a/ui/components/app/deposit-popover/deposit-popover.js +++ /dev/null @@ -1,240 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { useContext } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; - -import { I18nContext } from '../../../contexts/i18n'; -import { MetaMetricsContext } from '../../../contexts/metametrics'; -import { - NETWORK_TO_NAME_MAP, - BUYABLE_CHAINS_MAP, -} from '../../../../shared/constants/network'; -import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; - -import LogoMoonPay from '../../ui/logo/logo-moonpay'; -import LogoWyre from '../../ui/logo/logo-wyre'; -import LogoTransak from '../../ui/logo/logo-transak'; -import LogoCoinbasePay from '../../ui/logo/logo-coinbasepay'; -import LogoDepositEth from '../../ui/logo/logo-deposit-eth'; -import Popover from '../../ui/popover'; - -import { buy, showModal, hideWarning } from '../../../store/actions'; -import { - getIsTestnet, - getCurrentChainId, - getSelectedAddress, - getIsBuyableTransakChain, - getIsBuyableMoonPayChain, - getIsBuyableCoinbasePayChain, - getIsBuyableCoinbasePayToken, - getIsBuyableTransakToken, - getIsBuyableMoonpayToken, - getIsBuyableWyreToken, -} from '../../../selectors/selectors'; - -import OnRampItem from './on-ramp-item'; - -const DepositPopover = ({ onClose, token }) => { - const isTokenDeposit = Boolean(token); - - const t = useContext(I18nContext); - const trackEvent = useContext(MetaMetricsContext); - const dispatch = useDispatch(); - - const chainId = useSelector(getCurrentChainId); - const isTestnet = useSelector(getIsTestnet); - const address = useSelector(getSelectedAddress); - const isBuyableTransakChain = useSelector(getIsBuyableTransakChain); - const isBuyableMoonPayChain = useSelector(getIsBuyableMoonPayChain); - const isBuyableWyreChain = false; - const isBuyableCoinbasePayChain = useSelector(getIsBuyableCoinbasePayChain); - - const isTokenBuyableCoinbasePay = useSelector((state) => - getIsBuyableCoinbasePayToken(state, token?.symbol), - ); - const isTokenBuyableTransak = useSelector((state) => - getIsBuyableTransakToken(state, token?.symbol), - ); - const isTokenBuyableMoonpay = useSelector((state) => - getIsBuyableMoonpayToken(state, token?.symbol), - ); - const isTokenBuyableWyre = useSelector((state) => - getIsBuyableWyreToken(state, token?.symbol), - ); - - const networkName = NETWORK_TO_NAME_MAP[chainId]; - const symbol = token - ? token.symbol - : BUYABLE_CHAINS_MAP[chainId].nativeCurrency; - - const showAccountDetailModal = () => { - dispatch(showModal({ name: 'ACCOUNT_DETAILS' })); - }; - const hideWarningMessage = () => { - dispatch(hideWarning()); - }; - - const toCoinbasePay = () => { - dispatch( - buy({ service: 'coinbase', address, chainId, symbol: token?.symbol }), - ); - }; - const toTransak = () => { - dispatch( - buy({ service: 'transak', address, chainId, symbol: token?.symbol }), - ); - }; - const toMoonPay = () => { - dispatch( - buy({ service: 'moonpay', address, chainId, symbol: token?.symbol }), - ); - }; - const toWyre = () => { - dispatch(buy({ service: 'wyre', address, chainId, symbol: token?.symbol })); - }; - const toFaucet = () => dispatch(buy({ chainId })); - - const goToAccountDetailsModal = () => { - hideWarningMessage(); - showAccountDetailModal(); - onClose(); - }; - - return ( - -
    - } - title={t('buyCryptoWithCoinbasePay', [symbol])} - text={t('buyCryptoWithCoinbasePayDescription', [symbol])} - buttonLabel={t('continueToCoinbasePay')} - onButtonClick={() => { - trackEvent({ - category: EVENT.CATEGORIES.ACCOUNTS, - event: EVENT_NAMES.ONRAMP_PROVIDER_SELECTED, - properties: { - onramp_provider_type: EVENT.ONRAMP_PROVIDER_TYPES.COINBASE, - }, - }); - toCoinbasePay(); - }} - hide={ - isTokenDeposit - ? !isBuyableCoinbasePayChain || !isTokenBuyableCoinbasePay - : !isBuyableCoinbasePayChain - } - /> - } - title={t('buyCryptoWithTransak', [symbol])} - text={t('buyCryptoWithTransakDescription', [symbol])} - buttonLabel={t('continueToTransak')} - onButtonClick={() => { - trackEvent({ - category: EVENT.CATEGORIES.ACCOUNTS, - event: EVENT_NAMES.ONRAMP_PROVIDER_SELECTED, - properties: { - onramp_provider_type: EVENT.ONRAMP_PROVIDER_TYPES.TRANSAK, - }, - }); - toTransak(); - }} - hide={ - isTokenDeposit - ? !isBuyableTransakChain || !isTokenBuyableTransak - : !isBuyableTransakChain - } - /> - } - title={t('buyCryptoWithMoonPay', [symbol])} - text={t('buyCryptoWithMoonPayDescription', [symbol])} - buttonLabel={t('continueToMoonPay')} - onButtonClick={() => { - trackEvent({ - category: EVENT.CATEGORIES.ACCOUNTS, - event: EVENT_NAMES.ONRAMP_PROVIDER_SELECTED, - properties: { - onramp_provider_type: EVENT.ONRAMP_PROVIDER_TYPES.MOONPAY, - }, - }); - toMoonPay(); - }} - hide={ - isTokenDeposit - ? !isBuyableMoonPayChain || !isTokenBuyableMoonpay - : !isBuyableMoonPayChain - } - /> - } - title={t('buyWithWyre', [symbol])} - text={t('buyWithWyreDescription', [symbol])} - buttonLabel={t('continueToWyre')} - onButtonClick={() => { - trackEvent({ - category: EVENT.CATEGORIES.ACCOUNTS, - event: EVENT_NAMES.ONRAMP_PROVIDER_SELECTED, - properties: { - onramp_provider_type: EVENT.ONRAMP_PROVIDER_TYPES.WYRE, - }, - }); - toWyre(); - }} - hide={ - isTokenDeposit - ? !isBuyableWyreChain || !isTokenBuyableWyre - : !isBuyableWyreChain - } - /> - - } - title={t('directDepositCrypto', [symbol])} - text={t('directDepositCryptoExplainer', [symbol])} - buttonLabel={t('viewAccount')} - onButtonClick={() => { - trackEvent({ - category: EVENT.CATEGORIES.ACCOUNTS, - event: EVENT_NAMES.ONRAMP_PROVIDER_SELECTED, - properties: { - onramp_provider_type: EVENT.ONRAMP_PROVIDER_TYPES.SELF_DEPOSIT, - }, - }); - goToAccountDetailsModal(); - }} - hide={isTokenDeposit || !isBuyableWyreChain} - /> - - {networkName && ( - } - title={t('testFaucet')} - text={t('getEtherFromFaucet', [networkName])} - buttonLabel={t('getEther')} - onButtonClick={() => toFaucet()} - hide={!isTestnet} - /> - )} -
-
- ); -}; - -DepositPopover.propTypes = { - onClose: PropTypes.func.isRequired, - token: PropTypes.shape({ - address: PropTypes.string.isRequired, - decimals: PropTypes.number, - symbol: PropTypes.string, - image: PropTypes.string, - aggregators: PropTypes.array, - isERC721: PropTypes.bool, - }), -}; - -export default DepositPopover; diff --git a/ui/components/app/deposit-popover/index.js b/ui/components/app/deposit-popover/index.js deleted file mode 100644 index 63c24927f7ba..000000000000 --- a/ui/components/app/deposit-popover/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './deposit-popover'; diff --git a/ui/components/app/deposit-popover/index.scss b/ui/components/app/deposit-popover/index.scss deleted file mode 100644 index df0d11320197..000000000000 --- a/ui/components/app/deposit-popover/index.scss +++ /dev/null @@ -1,16 +0,0 @@ -.deposit-popover { - min-width: 328px; - max-width: 850px; - - @include screen-md-min { - width: 100% !important; - } - - &__on-ramp-item { - border-bottom: 1px solid var(--color-border-muted); - - &:last-child { - border-bottom: none; - } - } -} diff --git a/ui/components/app/deposit-popover/on-ramp-item.js b/ui/components/app/deposit-popover/on-ramp-item.js deleted file mode 100644 index ed41d53541e9..000000000000 --- a/ui/components/app/deposit-popover/on-ramp-item.js +++ /dev/null @@ -1,91 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import Button from '../../ui/button'; -import Box from '../../ui/box'; -import Typography from '../../ui/typography'; -import { - AlignItems, - DISPLAY, - FLEX_WRAP, - BLOCK_SIZES, - JustifyContent, -} from '../../../helpers/constants/design-system'; - -const OnRampItem = ({ - className, - logo, - title, - text, - buttonLabel, - onButtonClick, - hide = false, -}) => { - if (hide) { - return null; - } - return ( - - - - {logo} - - - - {title} - - {text} - - - - - - - ); -}; - -OnRampItem.propTypes = { - className: PropTypes.string, - logo: PropTypes.node.isRequired, - title: PropTypes.string.isRequired, - text: PropTypes.string.isRequired, - buttonLabel: PropTypes.string.isRequired, - onButtonClick: PropTypes.func.isRequired, - hide: PropTypes.bool, -}; - -export default OnRampItem; diff --git a/ui/components/app/wallet-overview/eth-overview.js b/ui/components/app/wallet-overview/eth-overview.js index 8281ec7f076f..0a86c4306f8c 100644 --- a/ui/components/app/wallet-overview/eth-overview.js +++ b/ui/components/app/wallet-overview/eth-overview.js @@ -1,4 +1,4 @@ -import React, { useContext, useState } from 'react'; +import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import classnames from 'classnames'; @@ -35,9 +35,9 @@ import { import Spinner from '../../ui/spinner'; import { startNewDraftTransaction } from '../../../ducks/send'; import { AssetType } from '../../../../shared/constants/transaction'; -import DepositPopover from '../deposit-popover'; import { Icon, ICON_NAMES } from '../../component-library'; import { IconColor } from '../../../helpers/constants/design-system'; +import useRamps from '../../../hooks/experiences/useRamps'; import WalletOverview from './wallet-overview'; const EthOverview = ({ className }) => { @@ -45,7 +45,6 @@ const EthOverview = ({ className }) => { const t = useContext(I18nContext); const trackEvent = useContext(MetaMetricsContext); const history = useHistory(); - const [showDepositPopover, setShowDepositPopover] = useState(false); const keyring = useSelector(getCurrentKeyring); const usingHardwareWallet = isHardwareKeyring(keyring?.type); const balanceIsCached = useSelector(isBalanceCached); @@ -56,183 +55,181 @@ const EthOverview = ({ className }) => { const primaryTokenImage = useSelector(getNativeCurrencyImage); const defaultSwapsToken = useSelector(getSwapsDefaultToken); + const { openBuyCryptoInPdapp } = useRamps(); + return ( - <> - {showDepositPopover && ( - setShowDepositPopover(false)} /> - )} - -
-
- {balance ? ( - - ) : ( - - )} - {balanceIsCached ? ( - * - ) : null} -
- {showFiat && balance && ( + +
+
+ {balance ? ( + ) : ( + )} + {balanceIsCached ? ( + * + ) : null}
- - } - buttons={ - <> - - } - disabled={!isBuyableChain} - label={t('buy')} - onClick={() => { - trackEvent({ - event: EVENT_NAMES.NAV_BUY_BUTTON_CLICKED, - category: EVENT.CATEGORIES.NAVIGATION, - properties: { - location: 'Home', - text: 'Buy', - }, - }); - setShowDepositPopover(true); - }} - /> - - } - label={t('send')} - onClick={() => { + {showFiat && balance && ( + + )} +
+ + } + buttons={ + <> + + } + disabled={!isBuyableChain} + data-testid="eth-overview-buy" + label={t('buy')} + onClick={() => { + openBuyCryptoInPdapp(); + trackEvent({ + event: EVENT_NAMES.NAV_BUY_BUTTON_CLICKED, + category: EVENT.CATEGORIES.NAVIGATION, + properties: { + location: 'Home', + text: 'Buy', + }, + }); + }} + /> + + } + label={t('send')} + onClick={() => { + trackEvent({ + event: EVENT_NAMES.NAV_SEND_BUTTON_CLICKED, + category: EVENT.CATEGORIES.NAVIGATION, + properties: { + token_symbol: 'ETH', + location: 'Home', + text: 'Send', + }, + }); + dispatch( + startNewDraftTransaction({ type: AssetType.native }), + ).then(() => { + history.push(SEND_ROUTE); + }); + }} + /> + + } + onClick={() => { + if (isSwapsChain) { trackEvent({ - event: EVENT_NAMES.NAV_SEND_BUTTON_CLICKED, - category: EVENT.CATEGORIES.NAVIGATION, + event: EVENT_NAMES.NAV_SWAP_BUTTON_CLICKED, + category: EVENT.CATEGORIES.SWAPS, properties: { token_symbol: 'ETH', - location: 'Home', - text: 'Send', + location: EVENT.SOURCE.SWAPS.MAIN_VIEW, + text: 'Swap', }, }); - dispatch( - startNewDraftTransaction({ type: AssetType.native }), - ).then(() => { - history.push(SEND_ROUTE); - }); - }} - /> - - } - onClick={() => { - if (isSwapsChain) { - trackEvent({ - event: EVENT_NAMES.NAV_SWAP_BUTTON_CLICKED, - category: EVENT.CATEGORIES.SWAPS, - properties: { - token_symbol: 'ETH', - location: EVENT.SOURCE.SWAPS.MAIN_VIEW, - text: 'Swap', - }, - }); - dispatch(setSwapsFromToken(defaultSwapsToken)); - if (usingHardwareWallet) { - global.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE); - } else { - history.push(BUILD_QUOTE_ROUTE); - } + dispatch(setSwapsFromToken(defaultSwapsToken)); + if (usingHardwareWallet) { + global.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE); + } else { + history.push(BUILD_QUOTE_ROUTE); } - }} - label={t('swap')} - tooltipRender={ - isSwapsChain - ? null - : (contents) => ( - - {contents} - - ) - } - /> - } - label={t('portfolio')} - onClick={() => { - const portfolioUrl = process.env.PORTFOLIO_URL; - global.platform.openTab({ - url: `${portfolioUrl}?metamaskEntry=ext`, - }); - trackEvent( - { - category: EVENT.CATEGORIES.HOME, - event: EVENT_NAMES.PORTFOLIO_LINK_CLICKED, - properties: { - url: portfolioUrl, - }, - }, - { - contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE], + }} + label={t('swap')} + tooltipRender={ + isSwapsChain + ? null + : (contents) => ( + + {contents} + + ) + } + /> + + } + label={t('portfolio')} + onClick={() => { + const portfolioUrl = process.env.PORTFOLIO_URL; + global.platform.openTab({ + url: `${portfolioUrl}?metamaskEntry=ext`, + }); + trackEvent( + { + category: EVENT.CATEGORIES.HOME, + event: EVENT_NAMES.PORTFOLIO_LINK_CLICKED, + properties: { + url: portfolioUrl, }, - ); - }} - /> - - } - className={className} - icon={} - /> - + }, + { + contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE], + }, + ); + }} + /> + + } + className={className} + icon={} + /> ); }; diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js new file mode 100644 index 000000000000..f32b002b16e3 --- /dev/null +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -0,0 +1,159 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; +import { renderWithProvider } from '../../../../test/jest/rendering'; +import { HardwareKeyringTypes } from '../../../../shared/constants/hardware-wallets'; +import EthOverview from './eth-overview'; + +// Mock BUYABLE_CHAINS_MAP +jest.mock('../../../../shared/constants/network', () => ({ + ...jest.requireActual('../../../../shared/constants/network'), + BUYABLE_CHAINS_MAP: { + // MAINNET + '0x1': { + nativeCurrency: 'ETH', + network: 'ethereum', + }, + // POLYGON + '0x89': { + nativeCurrency: 'MATIC', + network: 'polygon', + }, + }, +})); + +describe('EthOverview', () => { + const mockStore = { + metamask: { + provider: { + type: 'test', + chainId: CHAIN_IDS.MAINNET, + }, + cachedBalances: {}, + preferences: { + useNativeCurrencyAsPrimaryCurrency: true, + }, + identities: { + '0x1': { + address: '0x1', + }, + }, + accounts: { + '0x1': { + address: '0x1', + balance: '0x1F4', + }, + }, + selectedAddress: '0x1', + keyrings: [ + { + type: HardwareKeyringTypes.imported, + accounts: ['0x1', '0x2'], + }, + { + type: HardwareKeyringTypes.ledger, + accounts: [], + }, + ], + contractExchangeRates: {}, + }, + }; + + const store = configureMockStore([thunk])(mockStore); + const ETH_OVERVIEW_BUY = 'eth-overview-buy'; + + afterEach(() => { + store.clearActions(); + }); + + describe('EthOverview', () => { + beforeAll(() => { + jest.clearAllMocks(); + Object.defineProperty(global, 'platform', { + value: { + openTab: jest.fn(), + }, + }); + }); + + it('should always show the Buy button regardless of current chain Id', () => { + const { queryByTestId } = renderWithProvider(, store); + const buyButton = queryByTestId(ETH_OVERVIEW_BUY); + expect(buyButton).toBeInTheDocument(); + }); + + it('should have the Buy native token button disabled if chain id is not part of supported buyable chains', () => { + const mockedStoreWithUnbuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.FANTOM }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithUnbuyableChainId, + ); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId(ETH_OVERVIEW_BUY); + expect(buyButton).toBeInTheDocument(); + expect(buyButton).toBeDisabled(); + }); + + it('should have the Buy native token enabled if chain id is part of supported buyable chains', () => { + const mockedStoreWithUnbuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.POLYGON }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithUnbuyableChainId, + ); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId(ETH_OVERVIEW_BUY); + expect(buyButton).toBeInTheDocument(); + expect(buyButton).not.toBeDisabled(); + }); + + it('should open the Buy native token URI when clicking on Buy button for a buyable chain ID', async () => { + const mockedStoreWithBuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.POLYGON }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithBuyableChainId, + ); + + const openTabSpy = jest.spyOn(global.platform, 'openTab'); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId(ETH_OVERVIEW_BUY); + + expect(buyButton).toBeInTheDocument(); + expect(buyButton).not.toBeDisabled(); + + fireEvent.click(buyButton); + expect(openTabSpy).toHaveBeenCalledTimes(1); + + await waitFor(() => + expect(openTabSpy).toHaveBeenCalledWith({ + url: expect.stringContaining(`/buy?metamaskEntry=ext_buy_button`), + }), + ); + }); + }); +}); diff --git a/ui/components/app/wallet-overview/token-overview.js b/ui/components/app/wallet-overview/token-overview.js index e0dcc95ebca9..a53292b1c7d3 100644 --- a/ui/components/app/wallet-overview/token-overview.js +++ b/ui/components/app/wallet-overview/token-overview.js @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react'; +import React, { useContext, useEffect } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; @@ -19,10 +19,7 @@ import { setSwapsFromToken } from '../../../ducks/swaps/swaps'; import { getCurrentKeyring, getIsSwapsChain, - getIsBuyableCoinbasePayToken, - getIsBuyableTransakToken, - getIsBuyableMoonpayToken, - getIsBuyableWyreToken, + getIsBuyableChain, } from '../../../selectors'; import IconButton from '../../ui/icon-button'; @@ -35,7 +32,7 @@ import { CONTEXT_PROPS, } from '../../../../shared/constants/metametrics'; import { AssetType } from '../../../../shared/constants/transaction'; -import DepositPopover from '../deposit-popover'; +import useRamps from '../../../hooks/experiences/useRamps'; import { Icon, ICON_NAMES } from '../../component-library'; import { IconColor } from '../../../helpers/constants/design-system'; @@ -46,7 +43,6 @@ const TokenOverview = ({ className, token }) => { const t = useContext(I18nContext); const trackEvent = useContext(MetaMetricsContext); const history = useHistory(); - const [showDepositPopover, setShowDepositPopover] = useState(false); const keyring = useSelector(getCurrentKeyring); const usingHardwareWallet = isHardwareKeyring(keyring.type); const { tokensWithBalances } = useTokenTracker([token]); @@ -58,24 +54,10 @@ const TokenOverview = ({ className, token }) => { token.symbol, ); const isSwapsChain = useSelector(getIsSwapsChain); - const isTokenBuyableCoinbasePay = useSelector((state) => - getIsBuyableCoinbasePayToken(state, token.symbol), - ); - const isTokenBuyableTransak = useSelector((state) => - getIsBuyableTransakToken(state, token.symbol), - ); - const isTokenBuyableMoonpay = useSelector((state) => - getIsBuyableMoonpayToken(state, token.symbol), - ); - const isTokenBuyableWyre = useSelector((state) => - getIsBuyableWyreToken(state, token.symbol), - ); - const isBuyable = - isTokenBuyableCoinbasePay || - isTokenBuyableTransak || - isTokenBuyableMoonpay || - isTokenBuyableWyre; + const isBuyableChain = useSelector(getIsBuyableChain); + + const { openBuyCryptoInPdapp } = useRamps(); useEffect(() => { if (token.isERC721 && process.env.NFTS_V1) { @@ -89,184 +71,168 @@ const TokenOverview = ({ className, token }) => { }, [token.isERC721, token.address, dispatch]); return ( - <> - {showDepositPopover && ( - setShowDepositPopover(false)} - token={token} - /> - )} - + + + {formattedFiatBalance ? ( - {formattedFiatBalance ? ( - - ) : null} -
- } - buttons={ - <> - {isBuyable && ( - + ) : null} +
+ } + buttons={ + <> + + } + label={t('buy')} + data-testid="token-overview-buy" + onClick={() => { + openBuyCryptoInPdapp(); + trackEvent({ + event: EVENT_NAMES.NAV_BUY_BUTTON_CLICKED, + category: EVENT.CATEGORIES.NAVIGATION, + properties: { + location: 'Token Overview', + text: 'Buy', + }, + }); + }} + disabled={token.isERC721 || !isBuyableChain} + /> + { + trackEvent({ + event: EVENT_NAMES.NAV_SEND_BUTTON_CLICKED, + category: EVENT.CATEGORIES.NAVIGATION, + properties: { + token_symbol: token.symbol, + location: EVENT.SOURCE.SWAPS.TOKEN_VIEW, + text: 'Send', + }, + }); + try { + await dispatch( + startNewDraftTransaction({ + type: AssetType.token, + details: token, + }), + ); + history.push(SEND_ROUTE); + } catch (err) { + if (!err.message.includes(INVALID_ASSET_TYPE)) { + throw err; } - label={t('buy')} - onClick={() => { - trackEvent({ - event: 'Clicked Deposit: Token', - category: EVENT.CATEGORIES.NAVIGATION, - properties: { - action: 'Home', - legacy_event: true, - }, - }); - setShowDepositPopover(true); - }} - disabled={token.isERC721} + } + }} + Icon={ + - )} - { + } + label={t('send')} + data-testid="eth-overview-send" + disabled={token.isERC721} + /> + + } + onClick={() => { + if (isSwapsChain) { trackEvent({ - event: EVENT_NAMES.NAV_SEND_BUTTON_CLICKED, - category: EVENT.CATEGORIES.NAVIGATION, + event: EVENT_NAMES.NAV_SWAP_BUTTON_CLICKED, + category: EVENT.CATEGORIES.SWAPS, properties: { token_symbol: token.symbol, location: EVENT.SOURCE.SWAPS.TOKEN_VIEW, - text: 'Send', + text: 'Swap', }, }); - try { - await dispatch( - startNewDraftTransaction({ - type: AssetType.token, - details: token, - }), - ); - history.push(SEND_ROUTE); - } catch (err) { - if (!err.message.includes(INVALID_ASSET_TYPE)) { - throw err; - } - } - }} - Icon={ - - } - label={t('send')} - data-testid="eth-overview-send" - disabled={token.isERC721} - /> - - } - onClick={() => { - if (isSwapsChain) { - trackEvent({ - event: EVENT_NAMES.NAV_SWAP_BUTTON_CLICKED, - category: EVENT.CATEGORIES.SWAPS, - properties: { - token_symbol: token.symbol, - location: EVENT.SOURCE.SWAPS.TOKEN_VIEW, - text: 'Swap', - }, - }); - dispatch( - setSwapsFromToken({ - ...token, - address: token.address.toLowerCase(), - iconUrl: token.image, - balance, - string: balanceToRender, - }), - ); - if (usingHardwareWallet) { - global.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE); - } else { - history.push(BUILD_QUOTE_ROUTE); - } + dispatch( + setSwapsFromToken({ + ...token, + address: token.address.toLowerCase(), + iconUrl: token.image, + balance, + string: balanceToRender, + }), + ); + if (usingHardwareWallet) { + global.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE); + } else { + history.push(BUILD_QUOTE_ROUTE); } - }} - label={t('swap')} - tooltipRender={ - isSwapsChain - ? null - : (contents) => ( - - {contents} - - ) } - /> - - } - label={t('portfolio')} - data-testid="home__portfolio-site" - onClick={() => { - const portfolioUrl = process.env.PORTFOLIO_URL; - global.platform.openTab({ - url: `${portfolioUrl}?metamaskEntry=ext`, - }); - trackEvent( - { - category: EVENT.CATEGORIES.HOME, - event: EVENT_NAMES.PORTFOLIO_LINK_CLICKED, - properties: { - url: portfolioUrl, - }, - }, - { - contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE], + }} + label={t('swap')} + tooltipRender={ + isSwapsChain + ? null + : (contents) => ( + + {contents} + + ) + } + /> + + } + label={t('portfolio')} + data-testid="home__portfolio-site" + onClick={() => { + const portfolioUrl = process.env.PORTFOLIO_URL; + global.platform.openTab({ + url: `${portfolioUrl}?metamaskEntry=ext`, + }); + trackEvent( + { + category: EVENT.CATEGORIES.HOME, + event: EVENT_NAMES.PORTFOLIO_LINK_CLICKED, + properties: { + url: portfolioUrl, }, - ); - }} - /> - - } - className={className} - icon={ - - } - /> - + + } + className={className} + icon={ + + } + /> ); }; diff --git a/ui/components/app/wallet-overview/token-overview.test.js b/ui/components/app/wallet-overview/token-overview.test.js index 6c371b602fac..d0266ee1c3ff 100644 --- a/ui/components/app/wallet-overview/token-overview.test.js +++ b/ui/components/app/wallet-overview/token-overview.test.js @@ -1,15 +1,35 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; import { renderWithProvider } from '../../../../test/jest/rendering'; import { HardwareKeyringTypes } from '../../../../shared/constants/hardware-wallets'; import TokenOverview from './token-overview'; +// Mock BUYABLE_CHAINS_MAP +jest.mock('../../../../shared/constants/network', () => ({ + ...jest.requireActual('../../../../shared/constants/network'), + BUYABLE_CHAINS_MAP: { + // MAINNET + '0x1': { + nativeCurrency: 'ETH', + network: 'ethereum', + }, + // POLYGON + '0x89': { + nativeCurrency: 'MATIC', + network: 'polygon', + }, + }, +})); + describe('TokenOverview', () => { const mockStore = { metamask: { provider: { type: 'test', + chainId: CHAIN_IDS.MAINNET, }, preferences: { useNativeCurrencyAsPrimaryCurrency: true, @@ -41,13 +61,23 @@ describe('TokenOverview', () => { }); describe('TokenOverview', () => { + beforeAll(() => { + jest.clearAllMocks(); + Object.defineProperty(global, 'platform', { + value: { + openTab: jest.fn(), + }, + }); + }); + + const token = { + name: 'test', + isERC721: false, + address: '0x01', + symbol: 'test', + }; + it('should not show a modal when token passed in props is not an ERC721', () => { - const token = { - name: 'test', - isERC721: false, - address: '0x01', - symbol: 'test', - }; renderWithProvider(, store); const actions = store.getActions(); @@ -56,13 +86,11 @@ describe('TokenOverview', () => { it('should show ConvertTokenToNFT modal when token passed in props is an ERC721', () => { process.env.NFTS_V1 = true; - const token = { - name: 'test', + const nftToken = { + ...token, isERC721: true, - address: '0x01', - symbol: 'test', }; - renderWithProvider(, store); + renderWithProvider(, store); const actions = store.getActions(); expect(actions).toHaveLength(1); @@ -73,5 +101,136 @@ describe('TokenOverview', () => { }); process.env.NFTS_V1 = false; }); + + it('should always show the Buy button regardless of chain Id', () => { + const mockedStoreWithUnbuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.PALM }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithUnbuyableChainId, + ); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId('token-overview-buy'); + expect(buyButton).toBeInTheDocument(); + }); + + it('should always show the Buy button regardless of token type', () => { + process.env.NFTS_V1 = true; + const nftToken = { + ...token, + isERC721: true, + }; + + const { queryByTestId } = renderWithProvider( + , + store, + ); + const buyButton = queryByTestId('token-overview-buy'); + expect(buyButton).toBeInTheDocument(); + }); + + it('should have the Buy token button disabled if chain id is not part of supported buyable chains', () => { + const mockedStoreWithUnbuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.FANTOM }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithUnbuyableChainId, + ); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId('token-overview-buy'); + expect(buyButton).toBeInTheDocument(); + expect(buyButton).toBeDisabled(); + }); + + it('should have the Buy token button enabled if chain id is part of supported buyable chains', () => { + const mockedStoreWithBuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.POLYGON }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithBuyableChainId, + ); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId('token-overview-buy'); + expect(buyButton).toBeInTheDocument(); + expect(buyButton).not.toBeDisabled(); + }); + + it('should have the Buy token button disabled for ERC721 tokens', () => { + process.env.NFTS_V1 = true; + const nftToken = { + ...token, + isERC721: true, + }; + + const mockedStoreWithBuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.POLYGON }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithBuyableChainId, + ); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId('token-overview-buy'); + expect(buyButton).toBeInTheDocument(); + expect(buyButton).toBeDisabled(); + }); + + it('should open the buy crypto URL for a buyable chain ID', async () => { + const mockedStoreWithBuyableChainId = { + metamask: { + ...mockStore.metamask, + provider: { type: 'test', chainId: CHAIN_IDS.POLYGON }, + }, + }; + const mockedStore = configureMockStore([thunk])( + mockedStoreWithBuyableChainId, + ); + + const openTabSpy = jest.spyOn(global.platform, 'openTab'); + + const { queryByTestId } = renderWithProvider( + , + mockedStore, + ); + const buyButton = queryByTestId('token-overview-buy'); + expect(buyButton).toBeInTheDocument(); + expect(buyButton).not.toBeDisabled(); + + fireEvent.click(buyButton); + expect(openTabSpy).toHaveBeenCalledTimes(1); + + await waitFor(() => + expect(openTabSpy).toHaveBeenCalledWith({ + url: expect.stringContaining(`/buy?metamaskEntry=ext_buy_button`), + }), + ); + }); }); }); diff --git a/ui/components/ui/logo/README.mdx b/ui/components/ui/logo/README.mdx index 13dc54144ed3..ed9a9bfa8a88 100644 --- a/ui/components/ui/logo/README.mdx +++ b/ui/components/ui/logo/README.mdx @@ -1,7 +1,5 @@ import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; -import LogoWyre from './logo-wyre'; - # Logo Logo components that are theme compatible @@ -9,7 +7,3 @@ Logo components that are theme compatible - -## Props - - diff --git a/ui/components/ui/logo/__snapshots__/logo-moonpay.test.js.snap b/ui/components/ui/logo/__snapshots__/logo-moonpay.test.js.snap deleted file mode 100644 index 41518b5d6313..000000000000 --- a/ui/components/ui/logo/__snapshots__/logo-moonpay.test.js.snap +++ /dev/null @@ -1,21 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`LogoMoonPay renders the LogoMoonPay component 1`] = ` -
- - - - -
-`; diff --git a/ui/components/ui/logo/logo-coinbasepay.js b/ui/components/ui/logo/logo-coinbasepay.js deleted file mode 100644 index 2b23e7391a7c..000000000000 --- a/ui/components/ui/logo/logo-coinbasepay.js +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const LogoCoinbasePay = ({ - width = '100%', - className, - ariaLabel, - color = 'var(--color-text-default)', -}) => { - return ( - - - - - - - ); -}; - -LogoCoinbasePay.propTypes = { - /** - * The width of the logo. Defaults to 100% - */ - width: PropTypes.string, - /** - * The color of the logo defaults to var(--color-text-default) - */ - color: PropTypes.string, - /** - * Additional className to add to the root svg - */ - className: PropTypes.string, - /** - * Aria label to add to the logo component - */ - ariaLabel: PropTypes.string, -}; - -export default LogoCoinbasePay; diff --git a/ui/components/ui/logo/logo-deposit-eth.js b/ui/components/ui/logo/logo-deposit-eth.js deleted file mode 100644 index 3b108645bc19..000000000000 --- a/ui/components/ui/logo/logo-deposit-eth.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const LogoDepositEth = ({ - width = '100%', - color = 'var(--color-text-default)', - className, - ariaLabel, -}) => { - return ( - - - - - - - ); -}; - -LogoDepositEth.propTypes = { - /** - * The width of the logo. Defaults to 100% - */ - width: PropTypes.string, - /** - * The color of the logo defaults to var(--color-text-default) - */ - color: PropTypes.string, - /** - * Additional className to add to the root svg - */ - className: PropTypes.string, - /** - * Aria label to add to the logo component - */ - ariaLabel: PropTypes.string, -}; - -export default LogoDepositEth; diff --git a/ui/components/ui/logo/logo-moonpay.js b/ui/components/ui/logo/logo-moonpay.js deleted file mode 100644 index 781b30255370..000000000000 --- a/ui/components/ui/logo/logo-moonpay.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const COLOR_MOONPAY_CIRCLES = '#7D00FF'; - -const LogoMoonPay = ({ - width = '100%', - color = 'var(--color-text-default)', - className, - ariaLabel, -}) => { - return ( - - - - - ); -}; - -LogoMoonPay.propTypes = { - /** - * The width of the logo. Defaults to 100% - */ - width: PropTypes.string, - /** - * The color of the logo defaults to var(--color-text-default) - */ - color: PropTypes.string, - /** - * Additional className to add to the root svg - */ - className: PropTypes.string, - /** - * Aria label to add to the logo component - */ - ariaLabel: PropTypes.string, -}; - -export default LogoMoonPay; diff --git a/ui/components/ui/logo/logo-moonpay.test.js b/ui/components/ui/logo/logo-moonpay.test.js deleted file mode 100644 index afaabd4868ea..000000000000 --- a/ui/components/ui/logo/logo-moonpay.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -import { renderWithProvider } from '../../../../test/jest'; -import LogoMoonPay from './logo-moonpay'; - -describe('LogoMoonPay', () => { - it('renders the LogoMoonPay component', () => { - const { container } = renderWithProvider(); - expect(container).toMatchSnapshot(); - }); -}); diff --git a/ui/components/ui/logo/logo-transak.js b/ui/components/ui/logo/logo-transak.js deleted file mode 100644 index d0ea72dc6ad4..000000000000 --- a/ui/components/ui/logo/logo-transak.js +++ /dev/null @@ -1,107 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const LogoTransak = ({ width = '100%', className, ariaLabel }) => { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -LogoTransak.propTypes = { - /** - * The width of the logo. Defaults to 100% - */ - width: PropTypes.string, - /** - * Additional className to add to the root svg - */ - className: PropTypes.string, - /** - * Aria label to add to the logo component - */ - ariaLabel: PropTypes.string, -}; - -export default LogoTransak; diff --git a/ui/components/ui/logo/logo-wyre.js b/ui/components/ui/logo/logo-wyre.js deleted file mode 100644 index 860a56bd4a74..000000000000 --- a/ui/components/ui/logo/logo-wyre.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const LogoWyre = ({ width = '100%', color = 'var(--color-text-default)' }) => { - return ( - - - - - - - - ); -}; - -LogoWyre.propTypes = { - /** - * The width of the logo. Defaults to 100% - */ - width: PropTypes.string, - /** - * The color of the logo defaults to var(--color-text-default) - */ - color: PropTypes.string, -}; - -export default LogoWyre; diff --git a/ui/components/ui/logo/logo.stories.js b/ui/components/ui/logo/logo.stories.js index 4cb5769dc6af..2372c4258f53 100644 --- a/ui/components/ui/logo/logo.stories.js +++ b/ui/components/ui/logo/logo.stories.js @@ -7,11 +7,6 @@ import Card from '../card'; import Box from '../box'; import Typography from '../typography'; -import LogoCoinbasePay from './logo-coinbasepay'; -import LogoMoonPay from './logo-moonpay'; -import LogoWyre from './logo-wyre'; -import LogoTransak from './logo-transak'; -import LogoDepositEth from './logo-deposit-eth'; import LogoLedger from './logo-ledger'; import LogoQRBased from './logo-qr-based'; import LogoTrezor from './logo-trezor'; @@ -69,11 +64,6 @@ export const DefaultStory = (args) => ( gridTemplateColumns: 'repeat(auto-fill, 176px)', }} > - } /> - } /> - } /> - } /> - } /> } /> } /> } /> diff --git a/ui/helpers/utils/moonpay.test.js b/ui/helpers/utils/moonpay.test.js deleted file mode 100644 index bf13f500d85e..000000000000 --- a/ui/helpers/utils/moonpay.test.js +++ /dev/null @@ -1,33 +0,0 @@ -import { CHAIN_IDS } from '../../../shared/constants/network'; -import { formatMoonpaySymbol } from './moonpay'; - -describe('Moonpay Utils', () => { - describe('formatMoonpaySymbol', () => { - it('should return the same input if falsy input is provided', () => { - expect(formatMoonpaySymbol()).toBe(undefined); - expect(formatMoonpaySymbol(null)).toBe(null); - expect(formatMoonpaySymbol('')).toBe(''); - }); - - it('should return the symbol in uppercase if no chainId is provided', () => { - const result = formatMoonpaySymbol('ETH'); - expect(result).toStrictEqual('ETH'); - }); - - it('should return the symbol in uppercase if chainId is different than Avalanche/BSC/Polygon', () => { - const result = formatMoonpaySymbol('ETH', CHAIN_IDS.MAINNET); - expect(result).toStrictEqual('ETH'); - const result2 = formatMoonpaySymbol('CELO', CHAIN_IDS.CELO); - expect(result2).toStrictEqual('CELO'); - }); - - it('should return the symbol in uppercase with the network name if chainId is Avalanche/BSC/Polygon', () => { - const result = formatMoonpaySymbol('BNB', CHAIN_IDS.BSC); - expect(result).toStrictEqual('BNB_BSC'); - const result2 = formatMoonpaySymbol('MATIC', CHAIN_IDS.POLYGON); - expect(result2).toStrictEqual('MATIC_POLYGON'); - const result3 = formatMoonpaySymbol('AVAX', CHAIN_IDS.AVALANCHE); - expect(result3).toStrictEqual('AVAX_CCHAIN'); - }); - }); -}); diff --git a/ui/helpers/utils/moonpay.ts b/ui/helpers/utils/moonpay.ts deleted file mode 100644 index 30e5eb92d134..000000000000 --- a/ui/helpers/utils/moonpay.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - BUYABLE_CHAINS_MAP, - CHAIN_IDS, -} from '../../../shared/constants/network'; - -export const formatMoonpaySymbol = ( - symbol: string | null, - chainId: keyof typeof BUYABLE_CHAINS_MAP, -): string | null => { - if (!symbol) { - return symbol; - } - let _symbol = symbol; - if (chainId === CHAIN_IDS.POLYGON || chainId === CHAIN_IDS.BSC) { - _symbol = `${_symbol}_${BUYABLE_CHAINS_MAP?.[ - chainId - ]?.network.toUpperCase()}`; - } else if (chainId === CHAIN_IDS.AVALANCHE) { - _symbol = `${_symbol}_CCHAIN`; - } - return _symbol; -}; diff --git a/ui/hooks/experiences/useRamps.test.js b/ui/hooks/experiences/useRamps.test.js new file mode 100644 index 000000000000..f104094e8f95 --- /dev/null +++ b/ui/hooks/experiences/useRamps.test.js @@ -0,0 +1,82 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { useSelector } from 'react-redux'; +import useRamps from './useRamps'; + +jest.mock('react-redux'); + +jest.mock('./../../selectors', () => ({ + getCurrentChainId: jest.fn(), +})); + +jest.mock('../../../shared/constants/network', () => ({ + CHAIN_IDS: { + GOERLI: '5', + SEPOLIA: '10', + MAINNET: '1', + }, +})); + +describe('useRamps', () => { + beforeAll(() => { + jest.clearAllMocks(); + Object.defineProperty(global, 'platform', { + value: { + openTab: jest.fn(), + }, + }); + }); + + it('should open the buy crypto URL for GOERLI chain ID', () => { + const mockChainId = '5'; + const mockBuyURI = 'https://goerli-faucet.slock.it/'; + + useSelector.mockReturnValue(mockChainId); + const openTabSpy = jest.spyOn(global.platform, 'openTab'); + + const { result } = renderHook(() => useRamps()); + + expect(typeof result.current.openBuyCryptoInPdapp).toBe('function'); + + result.current.openBuyCryptoInPdapp(); + + expect(openTabSpy).toHaveBeenCalledWith({ + url: mockBuyURI, + }); + }); + + it('should open the buy crypto URL for SEPOLIA chain ID', () => { + const mockChainId = '10'; + const mockBuyURI = 'https://faucet.sepolia.dev/'; + + useSelector.mockReturnValue(mockChainId); + const openTabSpy = jest.spyOn(global.platform, 'openTab'); + + const { result } = renderHook(() => useRamps()); + + expect(typeof result.current.openBuyCryptoInPdapp).toBe('function'); + + result.current.openBuyCryptoInPdapp(); + + expect(openTabSpy).toHaveBeenCalledWith({ + url: mockBuyURI, + }); + }); + + it('should open the buy crypto URL for MAINNET chain ID', () => { + const mockChainId = '1'; + const mockBuyURI = `${process.env.PORTFOLIO_URL}/buy?metamaskEntry=ext_buy_button`; + + useSelector.mockReturnValue(mockChainId); + const openTabSpy = jest.spyOn(global.platform, 'openTab'); + + const { result } = renderHook(() => useRamps()); + + expect(typeof result.current.openBuyCryptoInPdapp).toBe('function'); + + result.current.openBuyCryptoInPdapp(); + + expect(openTabSpy).toHaveBeenCalledWith({ + url: mockBuyURI, + }); + }); +}); diff --git a/ui/hooks/experiences/useRamps.ts b/ui/hooks/experiences/useRamps.ts new file mode 100644 index 000000000000..3b8947486329 --- /dev/null +++ b/ui/hooks/experiences/useRamps.ts @@ -0,0 +1,37 @@ +import { useCallback } from 'react'; +import { useSelector } from 'react-redux'; +import { ChainId, CHAIN_IDS } from '../../../shared/constants/network'; +import { getCurrentChainId } from '../../selectors'; + +interface IUseRamps { + openBuyCryptoInPdapp: VoidFunction; + getBuyURI: (chainId: ChainId) => string; +} + +const portfolioUrl = process.env.PORTFOLIO_URL; + +const useRamps = (): IUseRamps => { + const chainId = useSelector(getCurrentChainId); + + const getBuyURI = useCallback((_chainId: ChainId) => { + switch (_chainId) { + case CHAIN_IDS.GOERLI: + return 'https://goerli-faucet.slock.it/'; + case CHAIN_IDS.SEPOLIA: + return 'https://faucet.sepolia.dev/'; + default: + return `${portfolioUrl}/buy?metamaskEntry=ext_buy_button`; + } + }, []); + + const openBuyCryptoInPdapp = useCallback(() => { + const buyUrl = getBuyURI(chainId); + global.platform.openTab({ + url: buyUrl, + }); + }, []); + + return { openBuyCryptoInPdapp, getBuyURI }; +}; + +export default useRamps; diff --git a/ui/pages/send/gas-display/gas-display.js b/ui/pages/send/gas-display/gas-display.js index 7cd31230fbc4..ab078b368d1e 100644 --- a/ui/pages/send/gas-display/gas-display.js +++ b/ui/pages/send/gas-display/gas-display.js @@ -1,4 +1,4 @@ -import React, { useContext, useState } from 'react'; +import React, { useContext } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import classNames from 'classnames'; @@ -26,7 +26,6 @@ import TransactionDetailItem from '../../../components/app/transaction-detail-it import { NETWORK_TO_NAME_MAP } from '../../../../shared/constants/network'; import TransactionDetail from '../../../components/app/transaction-detail'; import ActionableMessage from '../../../components/ui/actionable-message'; -import DepositPopover from '../../../components/app/deposit-popover'; import { getProvider, getPreferences, @@ -46,12 +45,17 @@ import { hexWEIToDecETH, hexWEIToDecGWEI, } from '../../../../shared/modules/conversion.utils'; +import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; +import { MetaMetricsContext } from '../../../contexts/metametrics'; +import useRamps from '../../../hooks/experiences/useRamps'; export default function GasDisplay({ gasError }) { const t = useContext(I18nContext); const dispatch = useDispatch(); const { estimateUsed } = useGasFeeContext(); - const [showDepositPopover, setShowDepositPopover] = useState(false); + const trackEvent = useContext(MetaMetricsContext); + + const { openBuyCryptoInPdapp } = useRamps(); const currentProvider = useSelector(getProvider); const isMainnet = useSelector(getIsMainnet); @@ -154,9 +158,6 @@ export default function GasDisplay({ gasError }) { return ( <> - {showDepositPopover && ( - setShowDepositPopover(false)} /> - )} { - setShowDepositPopover(true); + openBuyCryptoInPdapp(); + trackEvent({ + event: EVENT_NAMES.NAV_BUY_BUTTON_CLICKED, + category: EVENT.CATEGORIES.NAVIGATION, + properties: { + location: 'Gas Warning Insufficient Funds', + text: 'Buy', + }, + }); }} key={`${nativeCurrency}-buy-button`} > diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index cf6632c26672..a4f9bd78079d 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -64,7 +64,6 @@ import { getLedgerTransportStatus, } from '../ducks/app/app'; import { isEqualCaseInsensitive } from '../../shared/modules/string-utils'; -import { formatMoonpaySymbol } from '../helpers/utils/moonpay'; import { TransactionStatus } from '../../shared/constants/transaction'; import { getValueFromWeiHex, @@ -759,57 +758,6 @@ export function getIsBuyableChain(state) { const chainId = getCurrentChainId(state); return Object.keys(BUYABLE_CHAINS_MAP).includes(chainId); } - -export function getIsBuyableTransakChain(state) { - const chainId = getCurrentChainId(state); - return Boolean(BUYABLE_CHAINS_MAP?.[chainId]?.transakCurrencies); -} - -export function getIsBuyableTransakToken(state, symbol) { - const chainId = getCurrentChainId(state); - return Boolean( - BUYABLE_CHAINS_MAP?.[chainId]?.transakCurrencies?.includes(symbol), - ); -} - -export function getIsBuyableMoonpayToken(state, symbol) { - const chainId = getCurrentChainId(state); - const _symbol = formatMoonpaySymbol(symbol, chainId); - return Boolean( - BUYABLE_CHAINS_MAP?.[chainId]?.moonPay?.showOnlyCurrencies?.includes( - _symbol, - ), - ); -} - -export function getIsBuyableWyreToken(state, symbol) { - const chainId = getCurrentChainId(state); - return Boolean( - BUYABLE_CHAINS_MAP?.[chainId]?.wyre?.currencies.includes(symbol), - ); -} - -export function getIsBuyableMoonPayChain(state) { - const chainId = getCurrentChainId(state); - return Boolean(BUYABLE_CHAINS_MAP?.[chainId]?.moonPay); -} - -export function getIsBuyableWyreChain(state) { - const chainId = getCurrentChainId(state); - return Boolean(BUYABLE_CHAINS_MAP?.[chainId]?.wyre); -} -export function getIsBuyableCoinbasePayChain(state) { - const chainId = getCurrentChainId(state); - return Boolean(BUYABLE_CHAINS_MAP?.[chainId]?.coinbasePayCurrencies); -} - -export function getIsBuyableCoinbasePayToken(state, symbol) { - const chainId = getCurrentChainId(state); - return Boolean( - BUYABLE_CHAINS_MAP?.[chainId]?.coinbasePayCurrencies?.includes(symbol), - ); -} - export function getNativeCurrencyImage(state) { const nativeCurrency = getNativeCurrency(state)?.toUpperCase(); return NATIVE_CURRENCY_TOKEN_IMAGE_MAP[nativeCurrency]; diff --git a/ui/store/actionConstants.ts b/ui/store/actionConstants.ts index f83b1fd6ab03..8eca6c137e51 100644 --- a/ui/store/actionConstants.ts +++ b/ui/store/actionConstants.ts @@ -47,8 +47,6 @@ export const SET_HARDWARE_WALLET_DEFAULT_HD_PATH = export const SHOW_LOADING = 'SHOW_LOADING_INDICATION'; export const HIDE_LOADING = 'HIDE_LOADING_INDICATION'; -export const BUY = 'BUY'; - export const TOGGLE_ACCOUNT_MENU = 'TOGGLE_ACCOUNT_MENU'; // preferences diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 3d4808288433..f7dfae23c1af 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -14,7 +14,6 @@ import { PayloadAction } from '@reduxjs/toolkit'; import { GasFeeController } from '@metamask/gas-fee-controller'; import { PermissionsRequest } from '@metamask/permission-controller'; import { NonEmptyArray } from '@metamask/controller-utils'; -import getBuyUrl from '../../app/scripts/lib/buy-url'; import { getMethodDataAsync } from '../helpers/utils/transactions.util'; import switchDirection from '../../shared/lib/switch-direction'; import { @@ -76,12 +75,7 @@ import { TransactionMetaMetricsEvent, TransactionType, } from '../../shared/constants/transaction'; -import { - BUYABLE_CHAINS_MAP, - CurrencySymbol, - NetworkType, - RPCDefinition, -} from '../../shared/constants/network'; +import { NetworkType, RPCDefinition } from '../../shared/constants/network'; import { EtherDenomination } from '../../shared/constants/common'; import { isErrorWithMessage, @@ -2898,23 +2892,6 @@ export function showSendTokenPage(): Action { }; } -export function buy(opts: { - chainId: keyof typeof BUYABLE_CHAINS_MAP; - address?: string; - symbol?: CurrencySymbol; - service?: string; -}): ThunkAction { - return async (dispatch) => { - const url = await getBuyUrl(opts); - if (url) { - global.platform.openTab({ url }); - dispatch({ - type: actionConstants.BUY, - }); - } - }; -} - // TODO: Lift to shared folder when it makes sense interface TemporaryFeatureFlagDef { [feature: string]: boolean; diff --git a/yarn.lock b/yarn.lock index 23cc3f19cfd2..51eb8b9b671a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7197,6 +7197,16 @@ __metadata: languageName: node linkType: hard +"@types/hoist-non-react-statics@npm:^3.3.0": + version: 3.3.1 + resolution: "@types/hoist-non-react-statics@npm:3.3.1" + dependencies: + "@types/react": "*" + hoist-non-react-statics: ^3.3.0 + checksum: 2c0778570d9a01d05afabc781b32163f28409bb98f7245c38d5eaf082416fdb73034003f5825eb5e21313044e8d2d9e1f3fe2831e345d3d1b1d20bcd12270719 + languageName: node + linkType: hard + "@types/html-minifier-terser@npm:^5.0.0": version: 5.1.1 resolution: "@types/html-minifier-terser@npm:5.1.1" @@ -7519,6 +7529,18 @@ __metadata: languageName: node linkType: hard +"@types/react-redux@npm:^7.1.25": + version: 7.1.25 + resolution: "@types/react-redux@npm:7.1.25" + dependencies: + "@types/hoist-non-react-statics": ^3.3.0 + "@types/react": "*" + hoist-non-react-statics: ^3.3.0 + redux: ^4.0.0 + checksum: a61ec25cbf8bb3720850402d3c49493fcff4afb73ad447d161460b5d4c600c984ad48708e8564d2fd32052eaa3c3b3f655c5b300ce813429637cce9e5958329f + languageName: node + linkType: hard + "@types/react-transition-group@npm:^4.2.0": version: 4.4.0 resolution: "@types/react-transition-group@npm:4.4.0" @@ -24112,6 +24134,7 @@ __metadata: "@types/pump": ^1.1.1 "@types/react": ^16.9.53 "@types/react-dom": ^17.0.11 + "@types/react-redux": ^7.1.25 "@types/remote-redux-devtools": ^0.5.5 "@types/w3c-web-hid": ^1.0.3 "@types/watchify": ^3.11.1 From 56cba0974985d0b587759180a3020acbca54fbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Wed, 1 Mar 2023 09:38:15 +0000 Subject: [PATCH 19/19] [MMI] Adds mmi build type + manifest files and images (#17842) * MMI adds all mmi images, build type and manifest files * build-for-all-custodians * fix remove-fenced-code test * no need for axios * runs prettier * linter * MMI moving file out of codebase * MMI adds locale appNameMmi * MMI adds locale appNameMmi to verify-locale-strings --- app/_locales/en/messages.json | 4 + app/build-types/mmi/images/bitgo.svg | 4 + app/build-types/mmi/images/cactus.svg | 1 + .../mmi/images/check-green-solid.svg | 6 + .../mmi/images/close-red-solid.svg | 8 + .../mmi/images/compliance-logo-small.svg | 9 + .../mmi/images/compliance-logo.png | Bin 0 -> 142923 bytes .../mmi/images/curv-logo-horizontal-black.svg | 40 ++ app/build-types/mmi/images/curv-logo.svg | 1 + .../mmi/images/custodialWallet.svg | 3 + app/build-types/mmi/images/icon-128.png | Bin 0 -> 10225 bytes app/build-types/mmi/images/icon-16.png | Bin 0 -> 2366 bytes app/build-types/mmi/images/icon-19.png | Bin 0 -> 2559 bytes app/build-types/mmi/images/icon-32.png | Bin 0 -> 3402 bytes app/build-types/mmi/images/icon-38.png | Bin 0 -> 3815 bytes app/build-types/mmi/images/icon-48.png | Bin 0 -> 16021 bytes app/build-types/mmi/images/icon-512.png | Bin 0 -> 38334 bytes app/build-types/mmi/images/icon-64.png | Bin 0 -> 5665 bytes .../mmi/images/icons/red-triangle-exclaim.svg | 4 + app/build-types/mmi/images/info-logo.png | Bin 0 -> 17475 bytes app/build-types/mmi/images/jupiter.svg | 1 + .../mmi/images/logo/metamask-fox.svg | 31 ++ .../mmi/images/logo/mmi-logo-horizontal.svg | 47 +++ .../mmi/images/logo/mmi-logo-with-words.svg | 216 ++++++++++ .../mmi/images/logo/mmi-logo-xl.svg | 31 ++ app/build-types/mmi/images/logo/mmi-logo.svg | 31 ++ app/build-types/mmi/images/mmi-mascot.json | 322 +++++++++++++++ app/build-types/mmi/images/mmi-swaps.svg | 379 ++++++++++++++++++ app/build-types/mmi/images/parfin.svg | 25 ++ app/build-types/mmi/images/portfolio.svg | 9 + app/build-types/mmi/images/qredo.svg | 26 ++ app/build-types/mmi/manifest/_base.json | 26 ++ app/build-types/mmi/manifest/chrome.json | 4 + app/build-types/mmi/manifest/firefox.json | 7 + development/build/config.js | 1 + development/build/scripts.js | 4 + development/build/static.js | 6 + .../transforms/remove-fenced-code.test.js | 321 ++++++++------- development/lib/build-type.js | 1 + development/verify-locale-strings.js | 1 + ui/helpers/utils/build-types.js | 8 + 41 files changed, 1421 insertions(+), 156 deletions(-) create mode 100644 app/build-types/mmi/images/bitgo.svg create mode 100644 app/build-types/mmi/images/cactus.svg create mode 100644 app/build-types/mmi/images/check-green-solid.svg create mode 100644 app/build-types/mmi/images/close-red-solid.svg create mode 100644 app/build-types/mmi/images/compliance-logo-small.svg create mode 100644 app/build-types/mmi/images/compliance-logo.png create mode 100644 app/build-types/mmi/images/curv-logo-horizontal-black.svg create mode 100644 app/build-types/mmi/images/curv-logo.svg create mode 100644 app/build-types/mmi/images/custodialWallet.svg create mode 100644 app/build-types/mmi/images/icon-128.png create mode 100644 app/build-types/mmi/images/icon-16.png create mode 100644 app/build-types/mmi/images/icon-19.png create mode 100644 app/build-types/mmi/images/icon-32.png create mode 100644 app/build-types/mmi/images/icon-38.png create mode 100644 app/build-types/mmi/images/icon-48.png create mode 100644 app/build-types/mmi/images/icon-512.png create mode 100644 app/build-types/mmi/images/icon-64.png create mode 100644 app/build-types/mmi/images/icons/red-triangle-exclaim.svg create mode 100644 app/build-types/mmi/images/info-logo.png create mode 100644 app/build-types/mmi/images/jupiter.svg create mode 100644 app/build-types/mmi/images/logo/metamask-fox.svg create mode 100644 app/build-types/mmi/images/logo/mmi-logo-horizontal.svg create mode 100644 app/build-types/mmi/images/logo/mmi-logo-with-words.svg create mode 100644 app/build-types/mmi/images/logo/mmi-logo-xl.svg create mode 100644 app/build-types/mmi/images/logo/mmi-logo.svg create mode 100644 app/build-types/mmi/images/mmi-mascot.json create mode 100644 app/build-types/mmi/images/mmi-swaps.svg create mode 100644 app/build-types/mmi/images/parfin.svg create mode 100644 app/build-types/mmi/images/portfolio.svg create mode 100644 app/build-types/mmi/images/qredo.svg create mode 100644 app/build-types/mmi/manifest/_base.json create mode 100644 app/build-types/mmi/manifest/chrome.json create mode 100644 app/build-types/mmi/manifest/firefox.json diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 0aa328fe0ddd..7b3d3cf55837 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -351,6 +351,10 @@ "message": "MetaMask Flask", "description": "The name of the application (Flask)" }, + "appNameMmi": { + "message": "MetaMask Institutional", + "description": "The name of the application (MMI)" + }, "approve": { "message": "Approve spend limit" }, diff --git a/app/build-types/mmi/images/bitgo.svg b/app/build-types/mmi/images/bitgo.svg new file mode 100644 index 000000000000..21e237c3a652 --- /dev/null +++ b/app/build-types/mmi/images/bitgo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/build-types/mmi/images/cactus.svg b/app/build-types/mmi/images/cactus.svg new file mode 100644 index 000000000000..5abde4485e85 --- /dev/null +++ b/app/build-types/mmi/images/cactus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/build-types/mmi/images/check-green-solid.svg b/app/build-types/mmi/images/check-green-solid.svg new file mode 100644 index 000000000000..68c46196d1e7 --- /dev/null +++ b/app/build-types/mmi/images/check-green-solid.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/build-types/mmi/images/close-red-solid.svg b/app/build-types/mmi/images/close-red-solid.svg new file mode 100644 index 000000000000..728c70457a60 --- /dev/null +++ b/app/build-types/mmi/images/close-red-solid.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/build-types/mmi/images/compliance-logo-small.svg b/app/build-types/mmi/images/compliance-logo-small.svg new file mode 100644 index 000000000000..560b0b2a9cb1 --- /dev/null +++ b/app/build-types/mmi/images/compliance-logo-small.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/build-types/mmi/images/compliance-logo.png b/app/build-types/mmi/images/compliance-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..23250fd4acf2f4ee70ed443ecb15c50dd263cb86 GIT binary patch literal 142923 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

+?XB&~*I3Tm&Gdf!(g8a7 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/curv-logo.svg b/app/build-types/mmi/images/curv-logo.svg new file mode 100644 index 000000000000..37c06025b065 --- /dev/null +++ b/app/build-types/mmi/images/curv-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/build-types/mmi/images/custodialWallet.svg b/app/build-types/mmi/images/custodialWallet.svg new file mode 100644 index 000000000000..00f9bd3b0ca5 --- /dev/null +++ b/app/build-types/mmi/images/custodialWallet.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/build-types/mmi/images/icon-128.png b/app/build-types/mmi/images/icon-128.png new file mode 100644 index 0000000000000000000000000000000000000000..b63d1cd4f16ce43427fd1eb50cbec8650f846f14 GIT binary patch literal 10225 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%0ApJTQu>+={mq1tqlW~P47h$;WS=dw-@<5> z=zT@LwBdJI8+E&*o`;q=D*&qwJ%VD`;0T^()wY>a&`$i!w9qHF&WoX1ykU*Re$wb+ zpXJUjiG{$fi(aAHTfu>4Gl{-x#{C1gDIKV2TUs`rJO+>}G$y*c1fO)qu(taO9j9Cue{!!EA%gSIrsZMUNsUUS9*8RNBWtT zU1VeR$BzY`csk=^(zeV6&0bd!hDs(aBY=S!(=Xa4pzdS4 zvckP)nh>!1Lc8=@<{D&1NLlUQh-C*87z%rWY~=qeuUHGNtx?8-R1&NeG{P1DKo!!^ z``A2jT>)FZrduE7LPMM;?353m#ocDGVV$ zOWIW+m4Bm7B9B&SDggqhDSkaencW$F!#ppP?!Q%zJojQ(wv^o)eU-2RXR@|Pcog1q zJbPcbkWZmlwtji1sJ)$|WU@tdb8E{|%vbOoxZ>qNc$PM3%(!&>+Ev5cO+jScS@R=j zH`~fgF{ualh(^Ta20IbD)6zx}+9ZH14ki>jEE0U?C}dfnA*xA@TAui_m4{ zw|zzQRNpoyUVmN0AfX(Tph|td(@b>%RhLWql^u47=9WcSoR_+Bgq@I(p!hb1F*7{8 z`&o;F5(r(}sAx$;T)AdJWm@8arvcg0TdHw(9Jb}dl*qc}tvzLw0}6Opt*b>(PlFy4 zJ#Tk)mUeNTUS4cja?Y%&=G9E>;9%u68>iCuS9+`TGVt-~u@$X#{);!6zHt%R=t~ed zjOp?sARSL(q4-h?ein8Zqo$wVtC456^c6!YxF_#J6?QCN>eH{UT<`nG*a|qc%Z@JR z`j6WuCEb1%QW?BE?~YHOo(euH!uTFagU|;^^1a@7)hN&Lqrg5gHrFUWZaOLOCuW;8 z$rA&a_vn=(J8s(~1{CZ1)QBWV%&b3!x$qcUyJv&=SlxOYqwg8o;?c(Jr;pKxF zt>;wH0;dncPS)*BGs$(ydM`2gpI(Spc+9V{2LngPKSJ74-@K|(rU4y5;M2$j1ItEYbq)VH>+eXmjIh!gtrbr&ow$X5{;sID-00!J6?sOOygCFbAUWZsDk{QcKjoLKh zBKDE(p>NEa=hX&j4OT_l#<);)TT*X`rhX?#)~#wxYx8na$+UZEr{wc?+NMBddvX@2 zLoZL8wV4AC*`#!!obsa_S9X1bmQ1_{#eL0!r? z`YsI8(%%kEOa*hoRqEy}=v2-DtUCi^*673&s#xHfcw(Y7ywRqq8;oo&=kmReD)G*i z0xjKH`wp2Ab2c)9e38dBWPYCoaMu#z-V93Fx5e|e^~*2+-VM~TjtpRde6OC3yyq07 zW>u-byz&LkgFK~Or!HH&k-c0t)Bu#%G%VRG!~R=NFS~Gzjo46ha1a>QIEX6~`i^Sc zqIae~1VXqI29=8kGFsSOFoFAZ;5cU1z`keTNw$_z3G@`tAMP0aSzCv_$jaaX%km=| z&Cw?0Psd~zu!gK?eB4wOOIML?Y<4(B^<+?o55ZexgWhW9Tb`WOMS zX{rKvRMsfRaT@pdJu@Sw%M`#g~2pU{VI!B(h0MwMU6l>(IBmNH&zESZ2 literal 0 HcmV?d00001 diff --git a/app/build-types/mmi/images/icon-16.png b/app/build-types/mmi/images/icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..86f9caddad967b6ad91ecea68c2a51d67eeb9e94 GIT binary patch literal 2366 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 aec7%w{50mkhRVCUOm$^#r5Xk6@c#q;uY1J+ literal 0 HcmV?d00001 diff --git a/app/build-types/mmi/images/icon-512.png b/app/build-types/mmi/images/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..4046713753ac5e84bd5eb0014d54efda828ee201 GIT binary patch literal 38334 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 literal 0 HcmV?d00001 diff --git a/app/build-types/mmi/images/icon-64.png b/app/build-types/mmi/images/icon-64.png new file mode 100644 index 0000000000000000000000000000000000000000..278183b9e47eae882dc6443b7ea434bfc4de8347 GIT binary patch literal 5665 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 + + \ No newline at end of file diff --git a/app/build-types/mmi/images/info-logo.png b/app/build-types/mmi/images/info-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3b19236ab9349a064c2df5d06340bfa027fba74b GIT binary patch literal 17475 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 literal 0 HcmV?d00001 diff --git a/app/build-types/mmi/images/jupiter.svg b/app/build-types/mmi/images/jupiter.svg new file mode 100644 index 000000000000..6beef9c2f2e9 --- /dev/null +++ b/app/build-types/mmi/images/jupiter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/build-types/mmi/images/logo/metamask-fox.svg b/app/build-types/mmi/images/logo/metamask-fox.svg new file mode 100644 index 000000000000..cabdd95696f6 --- /dev/null +++ b/app/build-types/mmi/images/logo/metamask-fox.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/logo/mmi-logo-horizontal.svg b/app/build-types/mmi/images/logo/mmi-logo-horizontal.svg new file mode 100644 index 000000000000..4c6659098dfb --- /dev/null +++ b/app/build-types/mmi/images/logo/mmi-logo-horizontal.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/logo/mmi-logo-with-words.svg b/app/build-types/mmi/images/logo/mmi-logo-with-words.svg new file mode 100644 index 000000000000..9d266236e143 --- /dev/null +++ b/app/build-types/mmi/images/logo/mmi-logo-with-words.svg @@ -0,0 +1,216 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/logo/mmi-logo-xl.svg b/app/build-types/mmi/images/logo/mmi-logo-xl.svg new file mode 100644 index 000000000000..afa6ac519741 --- /dev/null +++ b/app/build-types/mmi/images/logo/mmi-logo-xl.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/logo/mmi-logo.svg b/app/build-types/mmi/images/logo/mmi-logo.svg new file mode 100644 index 000000000000..cabdd95696f6 --- /dev/null +++ b/app/build-types/mmi/images/logo/mmi-logo.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/mmi-mascot.json b/app/build-types/mmi/images/mmi-mascot.json new file mode 100644 index 000000000000..013cec092c3b --- /dev/null +++ b/app/build-types/mmi/images/mmi-mascot.json @@ -0,0 +1,322 @@ +{ + "chunks": [ + { + "color": [182, 202, 252], + "faces": [ + [17, 33, 10], + [17, 18, 34], + [34, 33, 17], + [10, 6, 17], + [11, 15, 31], + [31, 18, 11], + [18, 12, 11], + [14, 16, 40], + [40, 41, 14], + [59, 5, 35], + [35, 79, 59], + [67, 63, 77], + [67, 77, 76], + [76, 68, 67], + [63, 67, 58], + [64, 68, 75], + [75, 37, 64], + [68, 64, 66], + [14, 41, 37], + [37, 15, 14], + [5, 59, 40], + [40, 16, 5] + ] + }, + { + "color": [109, 149, 249], + "faces": [ + [31, 24, 18], + [6, 5, 16], + [16, 17, 6], + [24, 32, 33], + [33, 34, 24], + [5, 4, 35], + [75, 68, 71], + [58, 67, 40], + [40, 59, 58], + [71, 76, 77], + [77, 78, 71] + ] + }, + { + "color": [44, 86, 221], + "faces": [ + [0, 1, 2], + [2, 3, 0], + [4, 5, 2], + [6, 3, 2], + [2, 5, 6], + [7, 8, 9], + [10, 3, 6], + [10, 50, 7], + [7, 3, 10], + [7, 9, 3], + [49, 0, 9], + [3, 9, 0], + [53, 54, 55], + [55, 56, 53], + [57, 56, 55], + [58, 59, 55], + [55, 54, 58], + [60, 61, 62], + [63, 58, 54], + [63, 60, 89], + [60, 63, 54], + [60, 54, 61], + [88, 61, 53], + [54, 53, 61], + [2, 1, 4], + [55, 59, 57] + ] + }, + { + "color": [47, 52, 59], + "faces": [ + [36, 15, 37], + [37, 38, 36], + [31, 39, 22], + [22, 21, 31], + [31, 15, 36], + [36, 39, 31], + [75, 69, 26], + [26, 80, 75], + [75, 80, 38], + [38, 37, 75], + [38, 80, 39], + [39, 36, 38], + [39, 80, 26], + [26, 22, 39] + ] + }, + { + "color": [245, 247, 249], + "faces": [ + [21, 20, 24], + [24, 31, 21], + [69, 71, 70], + [71, 69, 75] + ] + }, + { + "color": [219, 229, 254], + "faces": [ + [19, 20, 21], + [21, 22, 19], + [20, 19, 23], + [23, 24, 20], + [23, 25, 24], + [19, 22, 26], + [26, 27, 19], + [23, 28, 29], + [23, 29, 30], + [25, 23, 30], + [29, 51, 52], + [52, 30, 29], + [27, 26, 69], + [69, 70, 27], + [70, 71, 72], + [72, 27, 70], + [72, 71, 73], + [51, 74, 72], + [52, 51, 72], + [73, 52, 72], + [19, 27, 74], + [74, 28, 19], + [51, 29, 28], + [28, 74, 51], + [74, 27, 72], + [28, 23, 19] + ] + }, + { + "color": [73, 123, 248], + "faces": [ + [24, 34, 18], + [16, 13, 12], + [12, 17, 16], + [13, 16, 11], + [71, 68, 76], + [40, 67, 66], + [66, 65, 40], + [65, 64, 40] + ] + }, + { + "color": [47, 52, 59], + "faces": [ + [11, 12, 13], + [64, 65, 66] + ] + }, + { + "color": [109, 149, 249], + "faces": [ + [14, 15, 11], + [11, 16, 14], + [17, 12, 18], + [41, 64, 37], + [67, 68, 66] + ] + }, + { + "color": [109, 149, 249], + "faces": [ + [35, 4, 42], + [4, 1, 42], + [42, 43, 44], + [44, 35, 42], + [45, 43, 42], + [42, 10, 45], + [30, 32, 24], + [24, 25, 30], + [30, 33, 32], + [33, 30, 10], + [44, 43, 46], + [43, 45, 47], + [47, 46, 43], + [48, 47, 45], + [45, 30, 48], + [30, 45, 10], + [49, 42, 0], + [8, 7, 42], + [50, 42, 7], + [50, 10, 42], + [1, 0, 42], + [42, 9, 8], + [42, 49, 9], + [64, 41, 40], + [57, 59, 79], + [79, 81, 57], + [57, 81, 56], + [82, 79, 35], + [35, 44, 82], + [81, 79, 82], + [82, 83, 81], + [84, 63, 81], + [81, 83, 84], + [44, 46, 85], + [85, 82, 44], + [52, 73, 71], + [71, 78, 52], + [52, 78, 77], + [77, 63, 52], + [82, 85, 83], + [83, 85, 86], + [86, 84, 83], + [87, 52, 84], + [84, 86, 87], + [52, 63, 84], + [88, 53, 81], + [62, 81, 60], + [89, 60, 81], + [89, 81, 63], + [56, 81, 53], + [81, 62, 61], + [81, 61, 88], + [48, 87, 86], + [86, 47, 48], + [47, 86, 85], + [85, 46, 47], + [48, 30, 52], + [52, 87, 48] + ] + } + ], + "positions": [ + [111.0246, 52.6046, 46.2259], + [114.025, 87.6733, 58.9818], + [66.192, 80.898, 55.3943], + [72.1133, 35.4918, 30.8714], + [97.8045, 116.561, 73.9788], + [16.7623, 58.0109, 58.0782], + [52.6089, 30.3641, 42.5561], + [106.8814, 31.9455, 46.9133], + [113.4846, 38.6049, 49.1215], + [108.6633, 43.2332, 46.3154], + [101.2166, 15.9822, 46.3082], + [16.6605, -16.2883, 93.6187], + [40.775, -10.2288, 85.2764], + [23.9269, -2.5103, 86.7365], + [11.1691, -7.0037, 99.3776], + [9.5692, -34.3939, 141.672], + [12.596, 7.1655, 88.741], + [61.1809, 8.8142, 76.9968], + [39.7195, -28.9271, 88.9638], + [13.7962, -68.5757, 132.057], + [15.2674, -62.32, 129.688], + [14.8446, -52.6096, 140.113], + [12.8917, -49.7716, 144.741], + [35.6042, -71.758, 81.0639], + [47.4625, -68.6061, 63.3697], + [38.2486, -64.7302, 38.9099], + [-12.8917, -49.7716, 144.741], + [-13.7962, -68.5757, 132.057], + [17.8021, -71.758, 81.0639], + [19.1243, -69.0168, 49.4201], + [38.2486, -66.2756, 17.7762], + [12.8928, -36.7035, 141.672], + [109.284, -93.5899, 27.8243], + [122.118, -36.8894, 35.025], + [67.7668, -30.197, 78.4178], + [33.1807, 101.852, 25.3186], + [9.4063, -35.5898, 150.722], + [-9.5692, -34.3939, 141.672], + [-9.4063, -35.5898, 150.722], + [11.4565, -37.8994, 150.722], + [-12.596, 7.1655, 88.741], + [-11.1691, -7.0037, 99.3776], + [70.2365, 62.8362, -3.9475], + [47.2634, 54.294, -27.4148], + [28.7302, 91.7311, -24.9726], + [69.1676, 6.5862, -12.7757], + [28.7302, 49.1003, -48.3596], + [31.903, 5.692, -47.822], + [35.0758, -34.4329, -16.2809], + [115.2841, 48.6815, 48.6841], + [110.8428, 28.4821, 49.1762], + [-19.1243, -69.0168, 49.4201], + [-38.2486, -66.2756, 17.7762], + [-111.0246, 52.6046, 46.2259], + [-72.1133, 35.4918, 30.8714], + [-66.192, 80.898, 55.3943], + [-114.025, 87.6733, 58.9818], + [-97.8045, 116.561, 73.9788], + [-52.6089, 30.3641, 42.5561], + [-16.7623, 58.0109, 58.0782], + [-106.8814, 31.9455, 46.9133], + [-108.6633, 43.2332, 46.3154], + [-113.4846, 38.6049, 49.1215], + [-101.2166, 15.9822, 46.3082], + [-16.6605, -16.2883, 93.6187], + [-23.9269, -2.5103, 86.7365], + [-40.775, -10.2288, 85.2764], + [-61.1809, 8.8142, 76.9968], + [-39.7195, -28.9271, 88.9638], + [-14.8446, -52.6096, 140.113], + [-15.2674, -62.32, 129.688], + [-47.4625, -68.6061, 63.3697], + [-35.6042, -71.758, 81.0639], + [-38.2486, -64.7302, 38.9099], + [-17.8021, -71.758, 81.0639], + [-12.8928, -36.7035, 141.672], + [-67.7668, -30.197, 78.4178], + [-122.118, -36.8894, 35.025], + [-109.284, -93.5899, 27.8243], + [-33.1807, 101.852, 25.3186], + [-11.4565, -37.8994, 150.722], + [-70.2365, 62.8362, -3.9475], + [-28.7302, 91.7311, -24.9726], + [-47.2634, 54.294, -27.4148], + [-69.1676, 6.5862, -12.7757], + [-28.7302, 49.1003, -48.3596], + [-31.903, 5.692, -47.822], + [-35.0758, -34.4329, -16.2809], + [-115.2841, 48.6815, 48.6841], + [-110.8428, 28.4821, 49.1762] + ] +} diff --git a/app/build-types/mmi/images/mmi-swaps.svg b/app/build-types/mmi/images/mmi-swaps.svg new file mode 100644 index 000000000000..6199bcb94956 --- /dev/null +++ b/app/build-types/mmi/images/mmi-swaps.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/parfin.svg b/app/build-types/mmi/images/parfin.svg new file mode 100644 index 000000000000..bf09f39b7bd2 --- /dev/null +++ b/app/build-types/mmi/images/parfin.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/images/portfolio.svg b/app/build-types/mmi/images/portfolio.svg new file mode 100644 index 000000000000..296366a8c7c8 --- /dev/null +++ b/app/build-types/mmi/images/portfolio.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/build-types/mmi/images/qredo.svg b/app/build-types/mmi/images/qredo.svg new file mode 100644 index 000000000000..4f3d182c9b59 --- /dev/null +++ b/app/build-types/mmi/images/qredo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build-types/mmi/manifest/_base.json b/app/build-types/mmi/manifest/_base.json new file mode 100644 index 000000000000..182929bb3928 --- /dev/null +++ b/app/build-types/mmi/manifest/_base.json @@ -0,0 +1,26 @@ +{ + "browser_action": { + "default_icon": { + "16": "images/icon-16.png", + "19": "images/icon-19.png", + "32": "images/icon-32.png", + "38": "images/icon-38.png", + "64": "images/icon-64.png", + "128": "images/icon-128.png", + "512": "images/icon-512.png" + }, + "default_title": "MetaMask Institutional" + }, + "icons": { + "16": "images/icon-16.png", + "19": "images/icon-19.png", + "32": "images/icon-32.png", + "38": "images/icon-38.png", + "48": "images/icon-48.png", + "64": "images/icon-64.png", + "128": "images/icon-128.png", + "512": "images/icon-512.png" + }, + "name": "__MSG_appNameMmi__", + "short_name": "__MSG_appNameMmi__" +} diff --git a/app/build-types/mmi/manifest/chrome.json b/app/build-types/mmi/manifest/chrome.json new file mode 100644 index 000000000000..40299207413d --- /dev/null +++ b/app/build-types/mmi/manifest/chrome.json @@ -0,0 +1,4 @@ +{ + "description": "This is the Institutional version of MetaMask Extension", + "name": "MetaMask Institutional" +} diff --git a/app/build-types/mmi/manifest/firefox.json b/app/build-types/mmi/manifest/firefox.json new file mode 100644 index 000000000000..46b068290921 --- /dev/null +++ b/app/build-types/mmi/manifest/firefox.json @@ -0,0 +1,7 @@ +{ + "applications": { + "gecko": { + "id": "webextension-mmi@metamask.io" + } + } +} diff --git a/development/build/config.js b/development/build/config.js index a400c8f7e171..d3c6c3964aee 100644 --- a/development/build/config.js +++ b/development/build/config.js @@ -104,6 +104,7 @@ async function getProductionConfig(buildType) { [BuildType.beta]: ['INFURA_BETA_PROJECT_ID', 'SEGMENT_BETA_WRITE_KEY'], [BuildType.flask]: ['INFURA_FLASK_PROJECT_ID', 'SEGMENT_FLASK_WRITE_KEY'], [BuildType.main]: ['INFURA_PROD_PROJECT_ID', 'SEGMENT_PROD_WRITE_KEY'], + [BuildType.mmi]: ['INFURA_MMI_PROJECT_ID', 'SEGMENT_MMI_WRITE_KEY'], }; for (const required of [ diff --git a/development/build/scripts.js b/development/build/scripts.js index ba1f49c3058e..742d72257c20 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -109,6 +109,8 @@ function getInfuraProjectId({ buildType, config, environment, testing }) { return config.INFURA_BETA_PROJECT_ID; } else if (buildType === BuildType.flask) { return config.INFURA_FLASK_PROJECT_ID; + } else if (buildType === BuildType.mmi) { + return config.INFURA_MMI_PROJECT_ID; } throw new Error(`Invalid build type: '${buildType}'`); } @@ -132,6 +134,8 @@ function getSegmentWriteKey({ buildType, config, environment }) { return config.SEGMENT_BETA_WRITE_KEY; } else if (buildType === BuildType.flask) { return config.SEGMENT_FLASK_WRITE_KEY; + } else if (buildType === BuildType.mmi) { + return config.SEGMENT_MMI_WRITE_KEY; } throw new Error(`Invalid build type: '${buildType}'`); } diff --git a/development/build/static.js b/development/build/static.js index 19018fcfef53..15fa0f06c1fe 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -50,6 +50,12 @@ module.exports = function createStaticAssetTasks({ dest: `images`, }, ], + [BuildType.mmi]: [ + { + src: './app/build-types/mmi/images/', + dest: `images`, + }, + ], }; if (Object.keys(additionalBuildTargets).includes(buildType)) { diff --git a/development/build/transforms/remove-fenced-code.test.js b/development/build/transforms/remove-fenced-code.test.js index d1214ca79fc2..c38550cd4a97 100644 --- a/development/build/transforms/remove-fenced-code.test.js +++ b/development/build/transforms/remove-fenced-code.test.js @@ -647,151 +647,133 @@ function getTestData() { ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) - Conditionally_Included - - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN Always_Included - Always_Included - Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +Conditionally_Included - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN Always_Included - Always_Included Always_Included - Always_Included - Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(desktop) +///: BEGIN:ONLY_INCLUDE_IN(flask) - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included Always_Included - Always_Included Always_Included +Always_Included +Always_Included +///: BEGIN:ONLY_INCLUDE_IN(desktop) +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included ///: BEGIN:ONLY_INCLUDE_IN(flask) - Conditionally_Included +Conditionally_Included Conditionally_Included - ///: END:ONLY_INCLUDE_IN - +///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(desktop) - Conditionally_Included Conditionally_Included - - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +///: END:ONLY_INCLUDE_IN `, extraContentWithFences: ` ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) - Conditionally_Included - - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN Always_Included - Always_Included - Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +Conditionally_Included - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN Always_Included - Always_Included Always_Included - Always_Included - Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(desktop) +///: BEGIN:ONLY_INCLUDE_IN(flask) - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +///: BEGIN:ONLY_INCLUDE_IN(desktop) +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) - Conditionally_Included +Conditionally_Included Conditionally_Included - ///: END:ONLY_INCLUDE_IN - +///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(desktop) - Conditionally_Included +Conditionally_Included Conditionally_Included - ///: END:ONLY_INCLUDE_IN - Always_Included - Always_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included Always_Included `, withoutFences: ` - Always_Included Always_Included - Always_Included Always_Included Always_Included - Always_Included - Always_Included Always_Included - Always_Included Always_Included - Always_Included - Always_Included Always_Included - Always_Included Always_Included - - +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included `, extraContentWithoutFences: ` - Always_Included Always_Included - Always_Included Always_Included Always_Included - Always_Included - Always_Included Always_Included - Always_Included Always_Included - Always_Included - Always_Included Always_Included - Always_Included Always_Included - - - Always_Included - Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included Always_Included `, }, @@ -802,31 +784,27 @@ Always_Included ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) - Conditionally_Included - - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN Always_Included +Always_Included +///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +Conditionally_Included +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included Always_Included - Always_Included Always_Included - Always_Included Always_Included - Always_Included - Always_Included Always_Included - Always_Included Always_Included - - `, true, ], @@ -835,41 +813,57 @@ Always_Included ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) - Conditionally_Included - - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN Always_Included - Always_Included - Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +Conditionally_Included - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included Always_Included - Always_Included Always_Included +///: BEGIN:ONLY_INCLUDE_IN(flask) +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included Always_Included - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) - Conditionally_Included +Conditionally_Included Conditionally_Included - ///: END:ONLY_INCLUDE_IN - +///: END:ONLY_INCLUDE_IN +`, + true, + ], + mmi: [ + ` +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included `, true, ], @@ -881,33 +875,29 @@ Conditionally_Included ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) - Conditionally_Included - - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN Always_Included +Always_Included +///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +Conditionally_Included +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included Always_Included - Always_Included Always_Included - Always_Included Always_Included - Always_Included - Always_Included Always_Included - Always_Included Always_Included - - - Always_Included - Always_Included Always_Included `, true, @@ -917,43 +907,62 @@ Always_Included ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) - Conditionally_Included - - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN Always_Included - Always_Included - Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +Conditionally_Included - Conditionally_Included - Conditionally_Included - ///: END:ONLY_INCLUDE_IN +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included Always_Included - Always_Included Always_Included +///: BEGIN:ONLY_INCLUDE_IN(flask) +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included Always_Included - Always_Included Always_Included - Always_Included Always_Included - ///: BEGIN:ONLY_INCLUDE_IN(flask) - Conditionally_Included +Conditionally_Included Conditionally_Included - ///: END:ONLY_INCLUDE_IN - - Always_Included - Always_Included +///: END:ONLY_INCLUDE_IN +Always_Included +Always_Included +Always_Included +`, + true, + ], + mmi: [ + ` +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included +Always_Included Always_Included `, true, diff --git a/development/lib/build-type.js b/development/lib/build-type.js index ea9b9228a79f..762b9af4587b 100644 --- a/development/lib/build-type.js +++ b/development/lib/build-type.js @@ -8,6 +8,7 @@ const BuildType = { desktop: 'desktop', flask: 'flask', main: 'main', + mmi: 'mmi', }; const BuildTypeInheritance = { diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index ac62e9be20d8..c6942bedc991 100755 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -235,6 +235,7 @@ async function verifyEnglishLocale() { 'appName', 'appNameBeta', 'appNameFlask', + 'appNameMmi', 'appDescription', ]; diff --git a/ui/helpers/utils/build-types.js b/ui/helpers/utils/build-types.js index ed849966a54e..9096e8217279 100644 --- a/ui/helpers/utils/build-types.js +++ b/ui/helpers/utils/build-types.js @@ -4,6 +4,9 @@ import flaskJson from '../../../app/build-types/flask/images/flask-mascot.json'; ///: BEGIN:ONLY_INCLUDE_IN(desktop) import desktopJson from '../../../app/build-types/desktop/images/desktop-mascot.json'; ///: END:ONLY_INCLUDE_IN +///: BEGIN:ONLY_INCLUDE_IN(mmi) +import mmiJson from '../../../app/build-types/mmi/images/mmi-mascot.json'; +///: END:ONLY_INCLUDE_IN const assetList = { main: { @@ -25,6 +28,11 @@ const assetList = { foxMeshJson: desktopJson, }, ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + mmi: { + foxMeshJson: mmiJson, + }, + ///: END:ONLY_INCLUDE_IN }; export function isBeta() {