From 430d0b3408343dd93d2e0895c86608ef21be2dfd Mon Sep 17 00:00:00 2001 From: SamuelSalas Date: Fri, 25 Oct 2024 10:00:41 -0600 Subject: [PATCH 01/90] test: Refactor SendLinkView.js & TokenOverview.js files to follow page object model (#11986) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We are aiming to refactor the page objects in the modal folder so that they strictly follow the page object model pattern. This would aide in providing more readable and help standardize the way we create our tests. Because of the amount of files remaining, this issue will focus on working on three files to refactor, as well as their respective testIDS. Files inside the scope for this batch: - SendLinkView.js - TokenOverview.js ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** Regression Test run: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/73c51633-f930-4f5f-874e-1d7338f508ee ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../UI/AssetOverview/AssetOverview.tsx | 7 +- .../UI/AssetOverview/Price/Price.tsx | 4 +- app/components/UI/Navbar/index.js | 6 +- app/components/UI/Transactions/index.js | 3 +- .../Asset/__snapshots__/index.test.js.snap | 1 - .../AssetDetailsActions.test.tsx | 18 +-- .../AssetDetailsActions.tsx | 21 ++-- e2e/pages/Receive/PaymentRequestQrModal.js | 19 +++ .../RequestPaymentModal.js | 0 e2e/pages/Receive/SendLinkView.js | 33 +++++ e2e/pages/SendLinkView.js | 34 ----- e2e/pages/TokenOverview.js | 117 ++++++++++-------- e2e/selectors/TokenOverview.selectors.js | 21 ++++ .../wallet/ImportTokenView.selectors.js | 1 - .../quarantine/swap-token-chart.failing.js | 2 +- e2e/specs/swaps/token-details.spec.js | 32 +++-- e2e/specs/wallet/request-token-flow.spec.js | 11 +- wdio/screen-objects/TokenOverviewScreen.js | 18 +-- .../Screens/TokenOverviewScreen.testIds.js | 9 -- wdio/step-definitions/send-flow.steps.js | 1 - 20 files changed, 193 insertions(+), 165 deletions(-) create mode 100644 e2e/pages/Receive/PaymentRequestQrModal.js rename e2e/pages/{modals => Receive}/RequestPaymentModal.js (100%) create mode 100644 e2e/pages/Receive/SendLinkView.js delete mode 100644 e2e/pages/SendLinkView.js create mode 100644 e2e/selectors/TokenOverview.selectors.js delete mode 100644 wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds.js diff --git a/app/components/UI/AssetOverview/AssetOverview.tsx b/app/components/UI/AssetOverview/AssetOverview.tsx index d6266bfbd57..2833c18f8ef 100644 --- a/app/components/UI/AssetOverview/AssetOverview.tsx +++ b/app/components/UI/AssetOverview/AssetOverview.tsx @@ -1,10 +1,9 @@ import { zeroAddress } from 'ethereumjs-util'; import React, { useCallback, useEffect } from 'react'; -import { Platform, TouchableOpacity, View } from 'react-native'; +import { TouchableOpacity, View } from 'react-native'; import { useDispatch, useSelector } from 'react-redux'; import { strings } from '../../../../locales/i18n'; -import { TOKEN_ASSET_OVERVIEW } from '../../../../wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds'; -import generateTestId from '../../../../wdio/utils/generateTestId'; +import { TokenOverviewSelectorsIDs } from '../../../../e2e/selectors/TokenOverview.selectors'; import { newAssetTransaction } from '../../../actions/transaction'; import AppConstants from '../../../core/AppConstants'; import Engine from '../../../core/Engine'; @@ -261,7 +260,7 @@ const AssetOverview: React.FC = ({ return ( {asset.hasBalanceError ? ( renderWarning() diff --git a/app/components/UI/AssetOverview/Price/Price.tsx b/app/components/UI/AssetOverview/Price/Price.tsx index f297a40115f..9d95b9e17b5 100644 --- a/app/components/UI/AssetOverview/Price/Price.tsx +++ b/app/components/UI/AssetOverview/Price/Price.tsx @@ -17,7 +17,7 @@ import Text, { import PriceChart from '../PriceChart/PriceChart'; import { distributeDataPoints } from '../PriceChart/utils'; import styleSheet from './Price.styles'; -import { TOKEN_PRICE } from '../../../../../wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds'; +import { TokenOverviewSelectorsIDs } from '../../../../../e2e/selectors/TokenOverview.selectors'; import { TokenI } from '../../Tokens/types'; interface PriceProps { @@ -90,7 +90,7 @@ const Price = ({ {asset.symbol} )} {!isNaN(price) && ( - + {isLoading ? ( diff --git a/app/components/UI/Navbar/index.js b/app/components/UI/Navbar/index.js index fd8aa98b1f8..aeda7315f1d 100644 --- a/app/components/UI/Navbar/index.js +++ b/app/components/UI/Navbar/index.js @@ -1118,7 +1118,7 @@ export function getImportTokenNavbarOptions( // eslint-disable-next-line react/jsx-no-bind navigation.pop()} style={styles.backButton} - testID={ImportTokenViewSelectorsIDs.BACK_BUTTON} + testID={CommonSelectorsIDs.BACK_ARROW_BUTTON} > navigation.pop()} style={styles.backButton} - testID={ImportTokenViewSelectorsIDs.BACK_BUTTON} + testID={CommonSelectorsIDs.BACK_ARROW_BUTTON} > - + {!this.state.ready || this.props.loading ? this.renderLoader() : this.renderList()} diff --git a/app/components/Views/Asset/__snapshots__/index.test.js.snap b/app/components/Views/Asset/__snapshots__/index.test.js.snap index 48af7238227..627aedf5a32 100644 --- a/app/components/Views/Asset/__snapshots__/index.test.js.snap +++ b/app/components/Views/Asset/__snapshots__/index.test.js.snap @@ -16,7 +16,6 @@ exports[`Asset should render correctly 1`] = ` "flex": 1, } } - testID="txn-screen" > { const mockOnBuy = jest.fn(); @@ -49,35 +43,35 @@ describe('AssetDetailsActions', () => { it('calls onBuy when the buy button is pressed', () => { const { getByTestId } = render(); - fireEvent.press(getByTestId(TOKEN_OVERVIEW_BUY_BUTTON)); + fireEvent.press(getByTestId(TokenOverviewSelectorsIDs.BUY_BUTTON)); expect(mockOnBuy).toHaveBeenCalled(); }); it('calls goToSwaps when the swap button is pressed', () => { const { getByTestId } = render(); - fireEvent.press(getByTestId(TOKEN_OVERVIEW_SWAP_BUTTON)); + fireEvent.press(getByTestId(TokenOverviewSelectorsIDs.SWAP_BUTTON)); expect(mockGoToSwaps).toHaveBeenCalled(); }); it('calls goToBridge when the bridge button is pressed', () => { const { getByTestId } = render(); - fireEvent.press(getByTestId(TOKEN_OVERVIEW_BRIDGE_BUTTON)); + fireEvent.press(getByTestId(TokenOverviewSelectorsIDs.BRIDGE_BUTTON)); expect(mockGoToBridge).toHaveBeenCalled(); }); it('calls onSend when the send button is pressed', () => { const { getByTestId } = render(); - fireEvent.press(getByTestId(TOKEN_OVERVIEW_SEND_BUTTON)); + fireEvent.press(getByTestId(TokenOverviewSelectorsIDs.SEND_BUTTON)); expect(mockOnSend).toHaveBeenCalled(); }); it('calls onReceive when the receive button is pressed', () => { const { getByTestId } = render(); - fireEvent.press(getByTestId(TOKEN_OVERVIEW_RECEIVE_BUTTON)); + fireEvent.press(getByTestId(TokenOverviewSelectorsIDs.RECEIVE_BUTTON)); expect(mockOnReceive).toHaveBeenCalled(); }); diff --git a/app/components/Views/AssetDetails/AssetDetailsActions/AssetDetailsActions.tsx b/app/components/Views/AssetDetails/AssetDetailsActions/AssetDetailsActions.tsx index ef3ed101777..c1919568a7c 100644 --- a/app/components/Views/AssetDetails/AssetDetailsActions/AssetDetailsActions.tsx +++ b/app/components/Views/AssetDetails/AssetDetailsActions/AssetDetailsActions.tsx @@ -1,22 +1,15 @@ import React from 'react'; -import { View, Platform } from 'react-native'; +import { View } from 'react-native'; import styleSheet from './AssetDetailsActions.styles'; import { useStyles } from '../../../../component-library/hooks'; import WalletAction from '../../../../components/UI/WalletAction'; import { strings } from '../../../../../locales/i18n'; -import generateTestId from '../../../../../wdio/utils/generateTestId'; import { IconName } from '../../../../component-library/components/Icons/Icon'; import { AvatarSize } from '../../../../component-library/components/Avatars/Avatar'; import Text, { TextVariant, } from '../../../../component-library/components/Texts/Text'; -import { - TOKEN_OVERVIEW_BRIDGE_BUTTON, - TOKEN_OVERVIEW_BUY_BUTTON, - TOKEN_OVERVIEW_RECEIVE_BUTTON, - TOKEN_OVERVIEW_SEND_BUTTON, - TOKEN_OVERVIEW_SWAP_BUTTON, -} from '../../../../../wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds'; +import { TokenOverviewSelectorsIDs } from '../../../../../e2e/selectors/TokenOverview.selectors'; export interface AssetDetailsActionsProps { displayBuyButton: boolean | undefined; @@ -49,7 +42,7 @@ export const AssetDetailsActions: React.FC = ({ onPress={onBuy} iconStyle={styles.icon} containerStyle={styles.containerStyle} - {...generateTestId(Platform, TOKEN_OVERVIEW_BUY_BUTTON)} + actionID={TokenOverviewSelectorsIDs.BUY_BUTTON} /> {strings('asset_overview.buy_button')} @@ -65,7 +58,7 @@ export const AssetDetailsActions: React.FC = ({ onPress={goToSwaps} iconStyle={styles.icon} containerStyle={styles.containerStyle} - {...generateTestId(Platform, TOKEN_OVERVIEW_SWAP_BUTTON)} + actionID={TokenOverviewSelectorsIDs.SWAP_BUTTON} /> {strings('asset_overview.swap')} @@ -80,7 +73,7 @@ export const AssetDetailsActions: React.FC = ({ onPress={goToBridge} iconStyle={styles.icon} containerStyle={styles.containerStyle} - {...generateTestId(Platform, TOKEN_OVERVIEW_BRIDGE_BUTTON)} + actionID={TokenOverviewSelectorsIDs.BRIDGE_BUTTON} /> {strings('asset_overview.bridge')} @@ -93,7 +86,7 @@ export const AssetDetailsActions: React.FC = ({ onPress={onSend} iconStyle={styles.icon} containerStyle={styles.containerStyle} - {...generateTestId(Platform, TOKEN_OVERVIEW_SEND_BUTTON)} + actionID={TokenOverviewSelectorsIDs.SEND_BUTTON} /> {strings('asset_overview.send_button')} @@ -106,7 +99,7 @@ export const AssetDetailsActions: React.FC = ({ onPress={onReceive} iconStyle={styles.icon} containerStyle={styles.containerStyle} - {...generateTestId(Platform, TOKEN_OVERVIEW_RECEIVE_BUTTON)} + actionID={TokenOverviewSelectorsIDs.RECEIVE_BUTTON} /> {strings('asset_overview.receive_button')} diff --git a/e2e/pages/Receive/PaymentRequestQrModal.js b/e2e/pages/Receive/PaymentRequestQrModal.js new file mode 100644 index 00000000000..580c35ef172 --- /dev/null +++ b/e2e/pages/Receive/PaymentRequestQrModal.js @@ -0,0 +1,19 @@ +import Matchers from '../../utils/Matchers'; +import Gestures from '../../utils/Gestures'; +import { SendLinkViewSelectorsIDs } from '../../selectors/SendLinkView.selectors'; + +class PaymentRequestQrModal { + get container() { + return Matchers.getElementByID(SendLinkViewSelectorsIDs.QR_MODAL); + } + + get closeButton() { + return Matchers.getElementByID(SendLinkViewSelectorsIDs.CLOSE_QR_MODAL_BUTTON); + } + + async tapCloseButton() { + await Gestures.waitAndTap(this.closeButton); + } +} + +export default new PaymentRequestQrModal(); diff --git a/e2e/pages/modals/RequestPaymentModal.js b/e2e/pages/Receive/RequestPaymentModal.js similarity index 100% rename from e2e/pages/modals/RequestPaymentModal.js rename to e2e/pages/Receive/RequestPaymentModal.js diff --git a/e2e/pages/Receive/SendLinkView.js b/e2e/pages/Receive/SendLinkView.js new file mode 100644 index 00000000000..73663c6bbbb --- /dev/null +++ b/e2e/pages/Receive/SendLinkView.js @@ -0,0 +1,33 @@ +import Matchers from '../../utils/Matchers'; +import Gestures from '../../utils/Gestures'; +import { SendLinkViewSelectorsIDs } from '../../selectors/SendLinkView.selectors'; + +class SendLinkView { + get container() { + return Matchers.getElementByID(SendLinkViewSelectorsIDs.CONTAINER_ID); + } + + get qrModal() { + return Matchers.getElementByID(SendLinkViewSelectorsIDs.QR_MODAL); + } + + get closeSendLinkButton() { + return Matchers.getElementByID(SendLinkViewSelectorsIDs.CLOSE_SEND_LINK_VIEW_BUTTON); + } + + get qrCodeButton() { + return device.getPlatform() === 'android' + ? Matchers.getElementByLabel(SendLinkViewSelectorsIDs.QR_CODE_BUTTON) + : Matchers.getElementByID(SendLinkViewSelectorsIDs.QR_CODE_BUTTON); + } + + async tapQRCodeButton() { + await Gestures.waitAndTap(this.qrCodeButton); + } + + async tapCloseSendLinkButton() { + await Gestures.waitAndTap(this.closeSendLinkButton); + } +} + +export default new SendLinkView(); diff --git a/e2e/pages/SendLinkView.js b/e2e/pages/SendLinkView.js deleted file mode 100644 index 82a1477bfb0..00000000000 --- a/e2e/pages/SendLinkView.js +++ /dev/null @@ -1,34 +0,0 @@ -import TestHelpers from '../helpers'; -import { SendLinkViewSelectorsIDs } from '../selectors/SendLinkView.selectors'; - -export default class SendLinkView { - static async tapQRCodeButton() { - if (device.getPlatform() === 'android') { - await TestHelpers.waitAndTapByLabel( - SendLinkViewSelectorsIDs.QR_CODE_BUTTON, - ); - } else { - await TestHelpers.tap(SendLinkViewSelectorsIDs.QR_CODE_BUTTON); - } - } - - static async isVisible() { - await TestHelpers.checkIfVisible(SendLinkViewSelectorsIDs.CONTAINER_ID); - } - - static async isNotVisible() { - await TestHelpers.checkIfNotVisible(SendLinkViewSelectorsIDs.CONTAINER_ID); - } - static async tapCloseSendLinkButton() { - await TestHelpers.tap(SendLinkViewSelectorsIDs.CLOSE_SEND_LINK_VIEW_BUTTON); - } - - // QR Modal - static async tapQRCodeCloseButton() { - await TestHelpers.tap(SendLinkViewSelectorsIDs.CLOSE_QR_MODAL_BUTTON); - } - - static async isQRModalVisible() { - await TestHelpers.checkIfVisible(SendLinkViewSelectorsIDs.QR_MODAL); - } -} diff --git a/e2e/pages/TokenOverview.js b/e2e/pages/TokenOverview.js index 433b8ad3aa2..25e22153919 100644 --- a/e2e/pages/TokenOverview.js +++ b/e2e/pages/TokenOverview.js @@ -1,83 +1,94 @@ -import TestHelpers from '../helpers'; +import Matchers from '../utils/Matchers'; +import Gestures from '../utils/Gestures'; import { - TOKEN_PRICE, - TOKEN_OVERVIEW_SEND_BUTTON, - TOKEN_OVERVIEW_RECEIVE_BUTTON, - TOKEN_OVERVIEW_BUY_BUTTON, - TOKEN_OVERVIEW_SWAP_BUTTON, -} from '../../wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds'; -import { ImportTokenViewSelectorsIDs } from '../selectors/wallet/ImportTokenView.selectors'; -import enContent from '../../locales/languages/en.json'; + TokenOverviewSelectorsIDs, + TokenOverviewSelectorsText +} from '../selectors/TokenOverview.selectors'; -const chartTimePeriod = [ - enContent.asset_overview.chart_time_period_navigation['1d'], - enContent.asset_overview.chart_time_period_navigation['1w'], - enContent.asset_overview.chart_time_period_navigation['1m'], - enContent.asset_overview.chart_time_period_navigation['3m'], - enContent.asset_overview.chart_time_period_navigation['1y'], - enContent.asset_overview.chart_time_period_navigation['3y'], -]; +class TokenOverview { + get container() { + return Matchers.getElementByID(TokenOverviewSelectorsIDs.TOKEN_PRICE); + } + + get tokenPrice() { + return Matchers.getElementByID(TokenOverviewSelectorsIDs.TOKEN_PRICE); + } + + get sendButton() { + return Matchers.getElementByID(TokenOverviewSelectorsIDs.SEND_BUTTON); + } + + get swapButton() { + return Matchers.getElementByID(TokenOverviewSelectorsIDs.SWAP_BUTTON); + } -export default class TokenOverview { - static async tapSendButton() { - await TestHelpers.waitAndTap(TOKEN_OVERVIEW_SEND_BUTTON); + get receiveButton() { + return Matchers.getElementByID(TokenOverviewSelectorsIDs.RECEIVE_BUTTON); } - static async tapSwapButton() { - await TestHelpers.waitAndTap(TOKEN_OVERVIEW_SWAP_BUTTON); + get noChartData() { + return Matchers.getElementByText(TokenOverviewSelectorsText.NO_CHART_DATA); } - static async scrollOnScreen() { - await TestHelpers.swipe(TOKEN_PRICE, 'up', 'fast', 0.6); + get chartPeriod1d() { + return Matchers.getElementByText(TokenOverviewSelectorsText['1d']); } - static async tapBackButton() { - await TestHelpers.waitAndTap(ImportTokenViewSelectorsIDs.BACK_BUTTON); + get chartPeriod1w() { + return Matchers.getElementByText(TokenOverviewSelectorsText['1w']); } - static async isVisible() { - await TestHelpers.checkIfVisible(TOKEN_OVERVIEW_SEND_BUTTON); + get chartPeriod1m() { + return Matchers.getElementByText(TokenOverviewSelectorsText['1m']); } - static async selectChart(chartPeriod) { - await TestHelpers.tapByText(chartPeriod); + get chartPeriod3m() { + return Matchers.getElementByText(TokenOverviewSelectorsText['3m']); } - static async checkIfChartIsVisible() { - for (const period of chartTimePeriod) { - await this.selectChart(period); - await TestHelpers.checkIfElementWithTextIsNotVisible( - enContent.asset_overview.no_chart_data.title, - ); - } + get chartPeriod1y() { + return Matchers.getElementByText(TokenOverviewSelectorsText['1y']); } - static async TokenQuoteIsNotZero() { - await TestHelpers.checkIfElementNotToHaveText(TOKEN_PRICE, '$0'); + get chartPeriod3y() { + return Matchers.getElementByText(TokenOverviewSelectorsText['3y']); } - static async TokenQuoteIsZero() { - await TestHelpers.checkIfHasText(TOKEN_PRICE, '$0'); + async tapSendButton() { + await Gestures.waitAndTap(this.sendButton); } - static async ChartNotVisible() { - await TestHelpers.checkIfElementWithTextIsVisible( - enContent.asset_overview.no_chart_data.title, - ); + async tapSwapButton() { + await Gestures.waitAndTap(this.swapButton); } - static async isReceiveButtonVisible() { - await TestHelpers.checkIfExists(TOKEN_OVERVIEW_RECEIVE_BUTTON); + + async scrollOnScreen() { + await Gestures.swipe(this.tokenPrice, 'up', 'fast', 0.6); } - static async isSendButtonVisible() { - await TestHelpers.checkIfExists(TOKEN_OVERVIEW_SEND_BUTTON); + async tapChartPeriod1d() { + await Gestures.waitAndTap(this.chartPeriod1d); } - static async isBuyButtonVisible() { - await TestHelpers.checkIfExists(TOKEN_OVERVIEW_BUY_BUTTON); + async tapChartPeriod1w() { + await Gestures.waitAndTap(this.chartPeriod1w); } - static async isSwapButtonVisible() { - await TestHelpers.checkIfExists(TOKEN_OVERVIEW_SWAP_BUTTON); + async tapChartPeriod1m() { + await Gestures.waitAndTap(this.chartPeriod1m); + } + + async tapChartPeriod3m() { + await Gestures.waitAndTap(this.chartPeriod3m); + } + + async tapChartPeriod1y() { + await Gestures.waitAndTap(this.chartPeriod1y); + } + + async tapChartPeriod3y() { + await Gestures.waitAndTap(this.chartPeriod3y); } } + +export default new TokenOverview(); diff --git a/e2e/selectors/TokenOverview.selectors.js b/e2e/selectors/TokenOverview.selectors.js new file mode 100644 index 00000000000..c268b88033b --- /dev/null +++ b/e2e/selectors/TokenOverview.selectors.js @@ -0,0 +1,21 @@ +import enContent from '../../locales/languages/en.json'; + +export const TokenOverviewSelectorsIDs = { + CONTAINER: 'token-asset-overview', + TOKEN_PRICE: 'token-price', + SEND_BUTTON: 'token-send-button', + RECEIVE_BUTTON: 'token-receive-button', + BUY_BUTTON: 'token-buy-button', + SWAP_BUTTON: 'token-swap-button', + BRIDGE_BUTTON: 'token-bridge-button', +}; + +export const TokenOverviewSelectorsText = { + NO_CHART_DATA: enContent.asset_overview.no_chart_data.title, + '1d': enContent.asset_overview.chart_time_period_navigation['1d'], + '1w': enContent.asset_overview.chart_time_period_navigation['1w'], + '1m': enContent.asset_overview.chart_time_period_navigation['1m'], + '3m': enContent.asset_overview.chart_time_period_navigation['3m'], + '1y': enContent.asset_overview.chart_time_period_navigation['1y'], + '3y': enContent.asset_overview.chart_time_period_navigation['3y'], +}; diff --git a/e2e/selectors/wallet/ImportTokenView.selectors.js b/e2e/selectors/wallet/ImportTokenView.selectors.js index 4ad9af6c348..4288e200383 100644 --- a/e2e/selectors/wallet/ImportTokenView.selectors.js +++ b/e2e/selectors/wallet/ImportTokenView.selectors.js @@ -10,7 +10,6 @@ export const ImportTokenViewSelectorsIDs = { DECIMAL_INPUT: 'input-token-decimal', ADDRESS_WARNING_MESSAGE: 'token-address-warning', PRECISION_WARNING_MESSAGE: 'token-decimals-warning', - BACK_BUTTON: 'asset-back-button', ADD_CONFIRM_CUSTOM_ASSET: 'add-confirm-custom-asset', ADD_CANCEL_ADD_CUSTOM_ASSET_MODAL: 'add-cancel-custom-asset-modal', NEXT_BUTTON: 'token-import-next-button', diff --git a/e2e/specs/quarantine/swap-token-chart.failing.js b/e2e/specs/quarantine/swap-token-chart.failing.js index a3ef99be5e6..4e9b7b534de 100644 --- a/e2e/specs/quarantine/swap-token-chart.failing.js +++ b/e2e/specs/quarantine/swap-token-chart.failing.js @@ -53,8 +53,8 @@ describe(Regression('Swap from Token view'), () => { await TabBarComponent.tapWallet(); await Assertions.checkIfVisible(WalletView.container); await WalletView.tapOnToken('Ethereum'); + await Assertions.checkIfVisible(TokenOverview.container); await TokenOverview.scrollOnScreen(); - await TokenOverview.isVisible(); await TokenOverview.tapSwapButton(); if (!swapOnboarded) await Onboarding.tapStartSwapping(); await Assertions.checkIfVisible(QuoteView.getQuotes); diff --git a/e2e/specs/swaps/token-details.spec.js b/e2e/specs/swaps/token-details.spec.js index f0de17126e9..b2f0db4ba99 100644 --- a/e2e/specs/swaps/token-details.spec.js +++ b/e2e/specs/swaps/token-details.spec.js @@ -7,6 +7,9 @@ import { switchToSepoliaNetwork, } from '../../viewHelper'; import { CustomNetworks } from '../../resources/networks.e2e'; +import Assertions from '../../utils/Assertions'; +import CommonView from '../../pages/CommonView'; + describe(SmokeSwaps('Token Chart Tests'), () => { beforeAll(async () => { @@ -20,19 +23,32 @@ describe(SmokeSwaps('Token Chart Tests'), () => { it('should view the token chart', async () => { await WalletView.tapOnToken(); - await TokenOverview.TokenQuoteIsNotZero(); - await TokenOverview.checkIfChartIsVisible(); + await Assertions.checkIfElementNotToHaveText(TokenOverview.tokenPrice, '$0'); + + await TokenOverview.tapChartPeriod1d(); + await Assertions.checkIfVisible(TokenOverview.chartPeriod1d); + await TokenOverview.tapChartPeriod1w(); + await Assertions.checkIfVisible(TokenOverview.chartPeriod1w); + await TokenOverview.tapChartPeriod1m(); + await Assertions.checkIfVisible(TokenOverview.chartPeriod1m); + await TokenOverview.tapChartPeriod3m(); + await Assertions.checkIfVisible(TokenOverview.chartPeriod3m); + await TokenOverview.tapChartPeriod1y(); + await Assertions.checkIfVisible(TokenOverview.chartPeriod1y); + await TokenOverview.tapChartPeriod3y(); + await Assertions.checkIfVisible(TokenOverview.chartPeriod3y); + await TokenOverview.scrollOnScreen(); - await TokenOverview.isReceiveButtonVisible(); - await TokenOverview.isSendButtonVisible(); - await TokenOverview.isSwapButtonVisible(); - await TokenOverview.tapBackButton(); + await Assertions.checkIfVisible(TokenOverview.receiveButton); + await Assertions.checkIfVisible(TokenOverview.sendButton); + await Assertions.checkIfVisible(TokenOverview.swapButton); + await CommonView.tapBackButton(); }); it('should not display the chart when using Sepolia test network', async () => { await switchToSepoliaNetwork(); await WalletView.tapOnToken(CustomNetworks.Sepolia.providerConfig.ticker); - await TokenOverview.ChartNotVisible(); - await TokenOverview.TokenQuoteIsZero(); + await Assertions.checkIfNotVisible(TokenOverview.noChartData); + await Assertions.checkIfElementToHaveText(TokenOverview.tokenPrice, '$0'); }); }); diff --git a/e2e/specs/wallet/request-token-flow.spec.js b/e2e/specs/wallet/request-token-flow.spec.js index 83f015797f8..01687985db2 100644 --- a/e2e/specs/wallet/request-token-flow.spec.js +++ b/e2e/specs/wallet/request-token-flow.spec.js @@ -1,11 +1,12 @@ 'use strict'; import { SmokeCore } from '../../tags'; -import SendLinkView from '../../pages/SendLinkView'; +import RequestPaymentModal from '../../pages/Receive/RequestPaymentModal'; +import SendLinkView from '../../pages/Receive/SendLinkView'; +import PaymentRequestQrModal from '../../pages/Receive/PaymentRequestQrModal'; import RequestPaymentView from '../../pages/RequestPaymentView'; import TabBarComponent from '../../pages/TabBarComponent'; import WalletActionsModal from '../../pages/modals/WalletActionsModal'; import ProtectYourWalletModal from '../../pages/modals/ProtectYourWalletModal'; -import RequestPaymentModal from '../../pages/modals/RequestPaymentModal'; import { loginToApp } from '../../viewHelper'; import { loadFixture, @@ -63,16 +64,16 @@ describe(SmokeCore('Request Token Flow with Unprotected Wallet'), () => { it('should request DAI amount', async () => { await RequestPaymentView.typeInTokenAmount(5.5); - await SendLinkView.isVisible(); + await Assertions.checkIfVisible(SendLinkView.container); }); it('should see DAI request QR code', async () => { await SendLinkView.tapQRCodeButton(); - await SendLinkView.isQRModalVisible(); + await Assertions.checkIfVisible(PaymentRequestQrModal.container); }); it('should close request', async () => { - await SendLinkView.tapQRCodeCloseButton(); + await PaymentRequestQrModal.tapCloseButton(); await SendLinkView.tapCloseSendLinkButton(); }); diff --git a/wdio/screen-objects/TokenOverviewScreen.js b/wdio/screen-objects/TokenOverviewScreen.js index 2fc17edb3b3..713da151acb 100644 --- a/wdio/screen-objects/TokenOverviewScreen.js +++ b/wdio/screen-objects/TokenOverviewScreen.js @@ -1,26 +1,14 @@ -import { - TOKEN_ASSET_OVERVIEW, - TOKEN_OVERVIEW_SEND_BUTTON, -} from './testIDs/Screens/TokenOverviewScreen.testIds.js'; import Selectors from '../helpers/Selectors'; import Gestures from '../helpers/Gestures'; -import { ImportTokenViewSelectorsIDs } from '../../e2e/selectors/wallet/ImportTokenView.selectors'; +import { TokenOverviewSelectorsIDs } from '../../e2e/selectors/TokenOverview.selectors'; class TokenOverviewScreen { get tokenAssetOverview() { - return Selectors.getElementByPlatform(TOKEN_ASSET_OVERVIEW); + return Selectors.getElementByPlatform(TokenOverviewSelectorsIDs.CONTAINER); } get sendButton() { - return Selectors.getElementByPlatform(TOKEN_OVERVIEW_SEND_BUTTON); - } - - get backButtonTokenOverview() { - return Selectors.getElementByPlatform(ImportTokenViewSelectorsIDs.BACK_BUTTON); - } - - async tapBackButton() { - await Gestures.waitAndTap(this.backButtonTokenOverview); + return Selectors.getElementByPlatform(TokenOverviewSelectorsIDs.SEND_BUTTON); } async isTokenOverviewVisible() { diff --git a/wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds.js b/wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds.js deleted file mode 100644 index c719ab1d7f1..00000000000 --- a/wdio/screen-objects/testIDs/Screens/TokenOverviewScreen.testIds.js +++ /dev/null @@ -1,9 +0,0 @@ -export const TOKEN_ASSET_OVERVIEW = 'token-asset-overview'; -export const TOKEN_PRICE = 'token-price'; -export const TOKEN_OVERVIEW_SEND_BUTTON = 'token-send-button'; -export const TOKEN_OVERVIEW_BRIDGE_BUTTON = 'token-bridge-button'; -export const TOKEN_OVERVIEW_RECEIVE_BUTTON = 'token-receive-button'; -export const TOKEN_OVERVIEW_BUY_BUTTON = 'token-buy-button'; -export const TOKEN_OVERVIEW_SWAP_BUTTON = 'token-swap-button'; -export const TOKEN_OVERVIEW_TXN_SCREEN = 'txn-screen'; - diff --git a/wdio/step-definitions/send-flow.steps.js b/wdio/step-definitions/send-flow.steps.js index 1ee8101ab79..231e31025ce 100644 --- a/wdio/step-definitions/send-flow.steps.js +++ b/wdio/step-definitions/send-flow.steps.js @@ -131,7 +131,6 @@ Then(/^I am taken to the token overview screen/, async () => { }); Then(/^I tap back from the Token overview page/, async () => { - await TokenOverviewScreen.tapBackButton(); await WalletMainScreen.isMainWalletViewVisible(); }); From 0460043a40f7bf40319b0986a2fb8beadd0679ba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:24:54 -0600 Subject: [PATCH 02/90] feat: 7.33.0 (#11616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the release candidate for version 7.33.0. The changelog will be found in another PR chore/7.33.0-Changelog. # Team sign-off checklist - [x] team-security - [x] team-platform - [x] team-snaps-platform - [x] team-sdk - [x] team-assets - [x] team-notifications - [x] team-confirmations - [x] team-design-system - [x] team-tiger - [x] team-wallet-framework - [x] team-stake - [x] team-accounts # Reference - Testing plan sheet - https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372 --------- Co-authored-by: metamaskbot Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Cal-L Co-authored-by: Nico MASSART Co-authored-by: Cal Leung Co-authored-by: Mpendulo Ndlovu Co-authored-by: sahar-fehri Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com> Co-authored-by: Brian Bergeron Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com> Co-authored-by: Pedro Pablo Aste Kompen Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com> Co-authored-by: sethkfman Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com> Co-authored-by: Aslau Mario-Daniel Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com> Co-authored-by: Brendan Kirby <124314512+bkirb@users.noreply.github.com> Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> Co-authored-by: Curtis David Co-authored-by: Jyoti Puri Co-authored-by: OGPoyraz Co-authored-by: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Co-authored-by: Vince Howard Co-authored-by: SamuelSalas Co-authored-by: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com> Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Co-authored-by: Xiaoming Wang <7315988+dawnseeker8@users.noreply.github.com> Co-authored-by: Vivek <106310394+vivek-consensys@users.noreply.github.com> Co-authored-by: Xiaoming Wang Co-authored-by: Matthew Walsh Co-authored-by: Frank von Hoven <141057783+frankvonhoven@users.noreply.github.com> Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com> Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com> Co-authored-by: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Co-authored-by: Salim TOUBAL Co-authored-by: Daniel Cross Co-authored-by: Jongsun Suh Co-authored-by: Michele Esposito Co-authored-by: Michele Esposito <34438276+mikesposito@users.noreply.github.com> Co-authored-by: Christopher Ferreira <104831203+christopherferreira9@users.noreply.github.com> Co-authored-by: AxelGes <34173844+AxelGes@users.noreply.github.com> Co-authored-by: Brian Nguyen Co-authored-by: Amitabh Aggarwal Co-authored-by: George Marshall Co-authored-by: Frederik Bolding Co-authored-by: JSoufer Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Kylan Hurt Co-authored-by: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Co-authored-by: Mark Stacey Co-authored-by: Gauthier Petetin Co-authored-by: Simon <9662464+siibars@users.noreply.github.com> Co-authored-by: Jack Clancy Co-authored-by: Alex Donesky Co-authored-by: Nicholas Ellul Co-authored-by: legobt <6wbvkn0j@anonaddy.me> Co-authored-by: tommasini --- CHANGELOG.md | 106 +- android/app/build.gradle | 4 +- app/store/index.ts | 2 +- app/util/sentry/utils.js | 2 +- attribution.txt | 1939 ++++++++++-------------- bitrise.yml | 8 +- ios/MetaMask.xcodeproj/project.pbxproj | 24 +- package.json | 2 +- 8 files changed, 959 insertions(+), 1128 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e992dae281..8db93d47c3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,112 @@ ## Current Main Branch -## 7.32.0 - Oct 7, 2024 +## 7.33.0 - Oct 17, 2024 +### Added +- [#11507](https://github.com/MetaMask/metamask-mobile/pull/11507): feat: 10550 Re-introduce test for measuring cold app start + JS bundle load time (#11507) +- [#11318](https://github.com/MetaMask/metamask-mobile/pull/11318): feat: app event manager and attribution id parameters (#11318) +- [#11445](https://github.com/MetaMask/metamask-mobile/pull/11445): feat: add the abilty to hide the disconnect all button as well as showing and hiding the accounts row when necessary (#11445) +- [#11386](https://github.com/MetaMask/metamask-mobile/pull/11386): feat(3299): add tracking to network switching and confirmation (#11386) +- [#11239](https://github.com/MetaMask/metamask-mobile/pull/11239): feat(2739): permission summary view gets the ability to disconnect all (#11239) +- [#11497](https://github.com/MetaMask/metamask-mobile/pull/11497): feat: simple key-> value component for text value type (#11497) +- [#11478](https://github.com/MetaMask/metamask-mobile/pull/11478): feat: adding title to confirmation page (#11478) +- [#11477](https://github.com/MetaMask/metamask-mobile/pull/11477): feat: adding footer section to confirmation page (#11477) +- [#11454](https://github.com/MetaMask/metamask-mobile/pull/11454): feat: adding very basic confirmation page hidden behind env var (#11454) +- [#11083](https://github.com/MetaMask/metamask-mobile/pull/11083): feat: bundle size check (#11083) +- [#11452](https://github.com/MetaMask/metamask-mobile/pull/11452): feat(ds): add ListItem top and bottom accessories (#11452) +- [#11387](https://github.com/MetaMask/metamask-mobile/pull/11387): feat: 10550 Re-introduce test for measuring cold app start + JS bundle load time (#11387) +- [#11464](https://github.com/MetaMask/metamask-mobile/pull/11464): feat: STAKE-804: build pooled staking empty state component (#11464) +- [#11399](https://github.com/MetaMask/metamask-mobile/pull/11399): feat: add learn more modal component for staking (#11399) +- [#11261](https://github.com/MetaMask/metamask-mobile/pull/11261): feat: STAKE-822 build your balance component (#11261) +- [#11294](https://github.com/MetaMask/metamask-mobile/pull/11294): feat: added KeyValueRow to component-library/components-temp (#11294) +- [#11185](https://github.com/MetaMask/metamask-mobile/pull/11185): feat: display ""Snaps (Beta)"" decorator tag in accounts list (#11185) +- [#10829](https://github.com/MetaMask/metamask-mobile/pull/10829): feat: Eth snap keyring (#10829) +- [#11455](https://github.com/MetaMask/metamask-mobile/pull/11455): feat: bootstrap a reset notifications feat (#11455) +- [#11466](https://github.com/MetaMask/metamask-mobile/pull/11466): feat: add support for external links (#11466) +- [#11429](https://github.com/MetaMask/metamask-mobile/pull/11429): feat: add timeout handler (#11429) +- [#11427](https://github.com/MetaMask/metamask-mobile/pull/11427): feat: add feature announcements channel for android (#11427) +- [#11069](https://github.com/MetaMask/metamask-mobile/pull/11069): feat: react native fast crypto for notifications (#11069) + +### Changed +- [#11379](https://github.com/MetaMask/metamask-mobile/pull/11379): refactor: rename the feature flag since it had a typo (#11379) +- [#11615](https://github.com/MetaMask/metamask-mobile/pull/11615): chore: exclude temporarily sentry SDK advisory (#11615) +- [#11577](https://github.com/MetaMask/metamask-mobile/pull/11577): ci: disable swaps e2e workflow (#11577) +- [#11350](https://github.com/MetaMask/metamask-mobile/pull/11350): chore: replace Segment patch by plugin (#11350) +- [#11287](https://github.com/MetaMask/metamask-mobile/pull/11287): chore: remove unused events (#11287) +- [#11517](https://github.com/MetaMask/metamask-mobile/pull/11517): chore: delete swaps token charts test (#11517) +- [#11515](https://github.com/MetaMask/metamask-mobile/pull/11515): test: disable swaps token charts regression tests (#11515) +- [#11504](https://github.com/MetaMask/metamask-mobile/pull/11504): chore: revert measuring with react native performance (#11504) +- [#11458](https://github.com/MetaMask/metamask-mobile/pull/11458): test: Merge Import Token flow methods and ids in just one folder and files (#11458) +- [#11492](https://github.com/MetaMask/metamask-mobile/pull/11492): chore(revert): Prevent redundant Sentry sourcemap uploads (#11492) +- [#11469](https://github.com/MetaMask/metamask-mobile/pull/11469): test: Remove E2E Tests for Features No Longer Present in the App (#11469) +- [#11425](https://github.com/MetaMask/metamask-mobile/pull/11425): chore: Add skip label to bypass sonarcloud (#11425) +- [#11275](https://github.com/MetaMask/metamask-mobile/pull/11275): chore(js-ts): Convert app/util/bytes.js to TypeScript (#11275) +- [#11418](https://github.com/MetaMask/metamask-mobile/pull/11418): chore: revert chore(js-ts): Migrate 37 0-error js files (#11418) +- [#10880](https://github.com/MetaMask/metamask-mobile/pull/10880): chore: Enable linting Pods and re-organize setup.mjs file (#10880) +- [#11311](https://github.com/MetaMask/metamask-mobile/pull/11311): chore(js-ts): Convert app/components/UI/Swaps/components/Ratio.js to TypeScript (#11311) +- [#11357](https://github.com/MetaMask/metamask-mobile/pull/11357): chore(js-ts): Convert app/components/Views/PickComponent/index.js to TypeScript (#11357) +- [#11446](https://github.com/MetaMask/metamask-mobile/pull/11446): chore(js-ts): Convert app/components/Views/MediaPlayer/Loader.js to TypeScript (#11446) +- [#11473](https://github.com/MetaMask/metamask-mobile/pull/11473): chore(js-ts): Convert app/components/Base/ModalHandler.js to TypeScript (#11473) +- [#11601](https://github.com/MetaMask/metamask-mobile/pull/11601): chore(js-ts): Convert app/components/Base/ListItem.js to TypeScript (#11601) +- [#11407](https://github.com/MetaMask/metamask-mobile/pull/11407): chore(js-ts): Convert app/util/jsonRpcRequest.js to TypeScript (#11407) +- [#11594](https://github.com/MetaMask/metamask-mobile/pull/11594): chore(js-ts): Convert app/component-library/components/Icons/Icon/scripts/generate-assets.js to TypeScript (#11594) +- [#11523](https://github.com/MetaMask/metamask-mobile/pull/11523): chore(js-ts): Convert app/components/UI/GenericButton/index.ios.js to TypeScript (#11523) +- [#11472](https://github.com/MetaMask/metamask-mobile/pull/11472): chore(js-ts): Convert app/components/UI/FadeView/index.js to TypeScript (#11472) +- [#11476](https://github.com/MetaMask/metamask-mobile/pull/11476): chore(js-ts): Convert app/components/UI/OnboardingProgress/index.js to TypeScript (#11476) +- [#11405](https://github.com/MetaMask/metamask-mobile/pull/11405): chore(js-ts): Convert app/util/browserScripts.js to TypeScript (#11405) +- [#11214](https://github.com/MetaMask/metamask-mobile/pull/11214): chore(js-ts): Migrate 37 0-error js files (#11214) +- [#11271](https://github.com/MetaMask/metamask-mobile/pull/11271): chore(js-ts): Convert app/components/UI/ComponentErrorBoundary/index.js to TypeScript (#11271) +- [#11299](https://github.com/MetaMask/metamask-mobile/pull/11299): chore(js-ts): Convert app/util/validators/index.js to TypeScript (#11299) +- [#11303](https://github.com/MetaMask/metamask-mobile/pull/11303): chore(js-ts): Convert app/components/Base/SelectorButton.js to TypeScript (#11303) +- [#11280](https://github.com/MetaMask/metamask-mobile/pull/11280): chore(js-ts): Convert app/components/UI/GenericButton/index.android.js to TypeScript (#11280) +- [#11273](https://github.com/MetaMask/metamask-mobile/pull/11273): chore(js-ts): Convert app/components/UI/OnboardingScreenWithBg/index.js to TypeScript (#11273) +- [#11272](https://github.com/MetaMask/metamask-mobile/pull/11272): chore(js-ts): Convert app/components/Base/ModalDragger.js to TypeScript (#11272) +- [#11308](https://github.com/MetaMask/metamask-mobile/pull/11308): chore(js-ts): Convert app/components/UI/BlockingActionModal/index.js to TypeScript (#11308) +- [#11305](https://github.com/MetaMask/metamask-mobile/pull/11305): chore(js-ts): Convert app/components/Base/Summary.js to TypeScript (#11305) +- [#11274](https://github.com/MetaMask/metamask-mobile/pull/11274): chore(js-ts): Convert app/components/UI/ConnectHeader/index.js to TypeScript (#11274) +- [#11334](https://github.com/MetaMask/metamask-mobile/pull/11334): chore: chore/7.32.0-Changelog (#11334) +- [#11483](https://github.com/MetaMask/metamask-mobile/pull/11483): chore: refactor e2e (#11483) +- [#11491](https://github.com/MetaMask/metamask-mobile/pull/11491): chore: Add UX CodeOwners responsibilities (#11491) +- [#11364](https://github.com/MetaMask/metamask-mobile/pull/11364): refactor(1702-2): auto detect nft component (#11364) +- [#11363](https://github.com/MetaMask/metamask-mobile/pull/11363): refactor(1702-1): auto detect tokens component (#11363) +- [#11329](https://github.com/MetaMask/metamask-mobile/pull/11329): chore: Add `@MetaMask/metamask-assets` to `CODEOWNERS` (#11329) +- [#10449](https://github.com/MetaMask/metamask-mobile/pull/10449): chore: remove installation of redundant detox-cli in bitrise (#10449) +- [#11111](https://github.com/MetaMask/metamask-mobile/pull/11111): chore(deps): Bump `@metamask/phishing-controller` from `^9.0.0` to `^12.0.1` (#11111) +- [#11375](https://github.com/MetaMask/metamask-mobile/pull/11375): chore(deps): Bump `@metamask/controller-utils` from `^10.0.0` to `^11.3.0` (#11375) +- [#11140](https://github.com/MetaMask/metamask-mobile/pull/11140): chore(deps): Bump `@metamask/smart-transactions-controller` from `11.0.0` to `^13.0.0` (#11140) +- [#11351](https://github.com/MetaMask/metamask-mobile/pull/11351): chore(deps): Bump `@metamask/keyring-controller` from `^16.1.0` to `^17.2.1` (#11351) +- [#11104](https://github.com/MetaMask/metamask-mobile/pull/11104): chore(deps): Bump `@metamask/address-book-controller` from `^4.0.1` to `^6.0.1` (#11104) +- [#10917](https://github.com/MetaMask/metamask-mobile/pull/10917): chore(ci): split out ci scripts and devDeps into separate project (#10917) +- [#11081](https://github.com/MetaMask/metamask-mobile/pull/11081): chore: Prevent redundant Sentry sourcemap uploads (#11081) +- [#11470](https://github.com/MetaMask/metamask-mobile/pull/11470): chore: [Design quality] Update token details (#11470) +- [#11439](https://github.com/MetaMask/metamask-mobile/pull/11439): chore: cherry-pick fix: ""chore(deps): Bump @metamask/base-controller from ^6.0.0 to ^7.0.0 (#11207)"" (#11439) +- [#11169](https://github.com/MetaMask/metamask-mobile/pull/11169): chore(deps): Bump `@metamask/signature-controller` from `^17.0.0` to `^19.1.0` +- [#11352](https://github.com/MetaMask/metamask-mobile/pull/11352): chore(deps): Bump `@metamask/accounts-controller` to `^18.2.1` +### Fixed +- [#11512](https://github.com/MetaMask/metamask-mobile/pull/11512): fix: android firebase docs template (#11512) +- [#11430](https://github.com/MetaMask/metamask-mobile/pull/11430): fix: refactor Logger usage (#11430) +- [#11250](https://github.com/MetaMask/metamask-mobile/pull/11250): fix: push notifications (#11250) +- [#11581](https://github.com/MetaMask/metamask-mobile/pull/11581): fix: Fix invalid browser url crash (#11581) +- [#11467](https://github.com/MetaMask/metamask-mobile/pull/11467): fix: Reorder prep_environment (#11467) +- [#11367](https://github.com/MetaMask/metamask-mobile/pull/11367): fix: Update steps of the methods that are no longer valid (#11367) +- [#11400](https://github.com/MetaMask/metamask-mobile/pull/11400): fix: Stop crowdin action from creating branches (#11400) +- [#11348](https://github.com/MetaMask/metamask-mobile/pull/11348): fix: splash screen image on android (#11348) +- [#11346](https://github.com/MetaMask/metamask-mobile/pull/11346): fix: splash screen image on android (#11346) +- [#11554](https://github.com/MetaMask/metamask-mobile/pull/11554): fix: Fix/use portfolio home page (#11554) +- [#11443](https://github.com/MetaMask/metamask-mobile/pull/11443): fix: react native quick crypto ios build bug (#11443) +- [#11325](https://github.com/MetaMask/metamask-mobile/pull/11325): fix: loader can display on top of login screen (#11325) +- [#11372](https://github.com/MetaMask/metamask-mobile/pull/11372): fix: origin spoofing vulnerability in signature prompts on iOS (#11372) +- [#11076](https://github.com/MetaMask/metamask-mobile/pull/11076): fix(2453): adjust UI details for account cell on wallet screen (#11076) +- [#11524](https://github.com/MetaMask/metamask-mobile/pull/11524): fix: fix duplicated network select (#11524) +- [#11411](https://github.com/MetaMask/metamask-mobile/pull/11411): fix: fix fixture builder network state (#11411) +- [#11380](https://github.com/MetaMask/metamask-mobile/pull/11380): fix: Unreadable Asset options (#11380) +- [#11321](https://github.com/MetaMask/metamask-mobile/pull/11321): fix: fix detect tokens performance (#11321) +- [#11401](https://github.com/MetaMask/metamask-mobile/pull/11401): fix: replace decomissioned cloudflare-ipfs.com with gateway.pinata.cloud (#11401) +- [#11552](https://github.com/MetaMask/metamask-mobile/pull/11552): fix(11481): android system alert respects dark mode themes (#11552) +- [#11518](https://github.com/MetaMask/metamask-mobile/pull/11518): fix(11482): incorrect QR code error (#11518) + +## 7.32.0 - Oct 7, 2024 ### Added - [#10294](https://github.com/MetaMask/metamask-mobile/pull/10294): feat: create redux slice for featureFlags (#10294) diff --git a/android/app/build.gradle b/android/app/build.gradle index 80ffad8fa28..f2379b86e80 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -173,8 +173,8 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1450 - versionName "7.32.0" + versionName "7.33.0" + versionCode 1460 testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/store/index.ts b/app/store/index.ts index a96eb65823e..32b3be171d9 100644 --- a/app/store/index.ts +++ b/app/store/index.ts @@ -72,7 +72,7 @@ const createStoreAndPersistor = async () => { /** * Initialize services after persist is completed */ - const onPersistComplete = async () => { + const onPersistComplete = () => { endTrace({ name: TraceName.StorageRehydration }); /** diff --git a/app/util/sentry/utils.js b/app/util/sentry/utils.js index 4662bd2d090..83325f7db93 100644 --- a/app/util/sentry/utils.js +++ b/app/util/sentry/utils.js @@ -500,7 +500,7 @@ export function setupSentry() { metricsOptIn === AGREED ? [ ...integrations, - new Sentry.ReactNativeTracing({ + new Sentry.reactNativeTracingIntegration({ routingInstrumentation, }), ] diff --git a/attribution.txt b/attribution.txt index 1bc68ddebd3..62a2458d8e2 100644 --- a/attribution.txt +++ b/attribution.txt @@ -23,13 +23,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -abs-svg-path -0.1.1 -license: MIT -authors: Jake Rosoman - ****************************** abstract-leveldown @@ -5373,13 +5366,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -babel-runtime -6.26.0 -license: MIT -authors: Sebastian McKenzie - ****************************** @babel/template @@ -9198,7 +9184,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************** @consensys/on-ramp-sdk -1.28.3 <> +1.28.5 <> license: ISC authors: undefined @@ -9608,31 +9594,6 @@ cookie-signature license: MIT authors: TJ Holowaychuk -****************************** - -core-js -2.6.12 -Copyright (c) 2014-2020 Denis Pushkarev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - ****************************** core-js-compat @@ -12497,26 +12458,6 @@ dlv license: MIT authors: Jason Miller (http://jasonformat.com) -****************************** - -dnode -1.2.2 -Copyright 2010 James Halliday (mail@substack.net) - -This project is free software released under the MIT license: -http://www.opensource.org/licenses/mit-license.php - - -****************************** - -dnode-protocol -0.2.2 -Copyright 2010 James Halliday (mail@substack.net) - -This project is free software released under the MIT license: -http://www.opensource.org/licenses/mit-license.php - - ****************************** doctrine @@ -22350,8 +22291,15 @@ THE SOFTWARE. ****************************** -ethjs-contract -0.2.3 +ethjs-ens +2.0.1 +license: ISC +authors: Dan Finlay + +****************************** + +ethjs-filter +0.1.5 The MIT License Copyright (c) 2016 Nick Dodson. nickdodson.com @@ -22377,15 +22325,90 @@ THE SOFTWARE. ****************************** -ethjs-ens -2.0.1 +ethjs-format +0.2.2 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +eth-json-rpc-errors +1.1.1 +MIT License + +Copyright (c) 2019 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +eth-json-rpc-filters +5.1.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +eth-json-rpc-middleware +4.3.0 license: ISC -authors: Dan Finlay +authors: undefined ****************************** -ethjs-filter -0.1.5 +ethjs-query +0.2.9 The MIT License Copyright (c) 2016 Nick Dodson. nickdodson.com @@ -22411,8 +22434,8 @@ THE SOFTWARE. ****************************** -ethjs-filter -0.1.8 +ethjs-rpc +0.1.5 The MIT License Copyright (c) 2016 Nick Dodson. nickdodson.com @@ -22438,8 +22461,8 @@ THE SOFTWARE. ****************************** -ethjs-format -0.2.2 +ethjs-schema +0.1.5 The MIT License Copyright (c) 2016 Nick Dodson. nickdodson.com @@ -22465,8 +22488,8 @@ THE SOFTWARE. ****************************** -ethjs-format -0.2.7 +ethjs-schema +0.2.1 The MIT License Copyright (c) 2016 Nick Dodson. nickdodson.com @@ -22492,387 +22515,122 @@ THE SOFTWARE. ****************************** -eth-json-rpc-errors -1.1.1 -MIT License - -Copyright (c) 2019 MetaMask - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -****************************** - -eth-json-rpc-filters -4.2.2 -ISC License - -Copyright (c) 2020 MetaMask - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -****************************** - -eth-json-rpc-middleware -4.3.0 -license: ISC -authors: undefined - -****************************** - -eth-json-rpc-middleware -6.0.0 -ISC License - -Copyright (c) 2020 MetaMask - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -****************************** - -ethjs-query -0.2.9 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-query -0.3.8 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-rpc -0.1.5 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-rpc -0.2.0 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-schema -0.1.5 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-schema -0.2.1 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-unit -0.1.6 -The MIT License (MIT) - -Copyright (c) 2016 Nick Dodson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-util -0.1.3 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -ethjs-util -0.1.6 -The MIT License - -Copyright (c) 2016 Nick Dodson. nickdodson.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -****************************** - -eth-method-registry -4.0.0 -ISC License - -Copyright (c) 2020 MetaMask - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -****************************** - -eth-phishing-detect -1.2.0 -# DON'T BE A DICK PUBLIC LICENSE - -> Version 1.1, December 2016 - -> Copyright (C) 2018 kumavis - -Everyone is permitted to copy and distribute verbatim or modified -copies of this license document. - -> DON'T BE A DICK PUBLIC LICENSE -> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -1. Do whatever you like with the original work, just don't be a dick. - - Being a dick includes - but is not limited to - the following instances: - - 1a. Outright copyright infringement - Don't just copy this and change the name. - 1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. - 1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. - -2. If you become rich through modifications, related works/services, or supporting the original work, -share the love. Only a dick would make loads off this work and not buy the original work's -creator(s) a pint. - -3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes -you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. - - -****************************** - -eth-query -2.1.2 -license: ISC -authors: undefined - -****************************** - -eth-rpc-errors -3.0.0 +ethjs-util +0.1.3 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +ethjs-util +0.1.6 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +eth-method-registry +4.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +eth-phishing-detect +1.2.0 +# DON'T BE A DICK PUBLIC LICENSE + +> Version 1.1, December 2016 + +> Copyright (C) 2018 kumavis + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document. + +> DON'T BE A DICK PUBLIC LICENSE +> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +1. Do whatever you like with the original work, just don't be a dick. + + Being a dick includes - but is not limited to - the following instances: + + 1a. Outright copyright infringement - Don't just copy this and change the name. + 1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. + 1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. + +2. If you become rich through modifications, related works/services, or supporting the original work, +share the love. Only a dick would make loads off this work and not buy the original work's +creator(s) a pint. + +3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes +you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. + + +****************************** + +eth-query +2.1.2 +license: ISC +authors: undefined + +****************************** + +eth-rpc-errors +3.0.0 MIT License Copyright (c) 2019 MetaMask @@ -24229,6 +23987,13 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +firebase +10.12.2 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + ****************************** firebase @@ -24238,6 +24003,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/analytics +0.10.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/analytics 0.10.5 license: Apache-2.0 @@ -24245,6 +24017,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/analytics-compat +0.2.10 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/analytics-compat 0.2.11 license: Apache-2.0 @@ -24259,6 +24038,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/app +0.10.5 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/app 0.10.6 license: Apache-2.0 @@ -24266,6 +24052,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/app-check +0.8.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/app-check 0.8.5 license: Apache-2.0 @@ -24273,6 +24066,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/app-check-compat +0.3.11 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/app-check-compat 0.3.12 license: Apache-2.0 @@ -24294,6 +24094,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/app-compat +0.2.35 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/app-compat 0.2.36 license: Apache-2.0 @@ -24308,6 +24115,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/auth +1.7.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/auth 1.7.5 license: Apache-2.0 @@ -24322,6 +24136,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/auth-compat +0.5.9 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/auth-interop-types 0.2.3 license: Apache-2.0 @@ -24336,6 +24157,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/component +0.6.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/component 0.6.8 license: Apache-2.0 @@ -24343,6 +24171,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/database +1.0.5 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/database 1.0.6 license: Apache-2.0 @@ -24350,6 +24185,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/database-compat +1.0.5 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/database-compat 1.0.6 license: Apache-2.0 @@ -24357,6 +24199,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/database-types +1.0.3 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/database-types 1.0.4 license: Apache-2.0 @@ -24364,6 +24213,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/firestore +4.6.3 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/firestore 4.6.4 license: Apache-2.0 @@ -24371,6 +24227,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/firestore-compat +0.3.32 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/firestore-compat 0.3.33 license: Apache-2.0 @@ -24385,6 +24248,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/functions +0.11.5 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/functions 0.11.6 license: Apache-2.0 @@ -24392,6 +24262,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/functions-compat +0.3.11 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/functions-compat 0.3.12 license: Apache-2.0 @@ -24406,6 +24283,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/installations +0.6.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/installations 0.6.8 license: Apache-2.0 @@ -24413,6 +24297,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/installations-compat +0.2.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/installations-compat 0.2.8 license: Apache-2.0 @@ -24441,6 +24332,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/messaging +0.12.9 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/messaging-compat 0.2.10 license: Apache-2.0 @@ -24448,6 +24346,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/messaging-compat +0.2.9 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/messaging-interop-types 0.2.2 license: Apache-2.0 @@ -24455,6 +24360,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/performance +0.6.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/performance 0.6.8 license: Apache-2.0 @@ -24462,6 +24374,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/performance-compat +0.2.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/performance-compat 0.2.8 license: Apache-2.0 @@ -24476,6 +24395,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/remote-config +0.4.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/remote-config 0.4.8 license: Apache-2.0 @@ -24483,6 +24409,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/remote-config-compat +0.2.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/remote-config-compat 0.2.8 license: Apache-2.0 @@ -24497,6 +24430,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/storage +0.12.5 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/storage 0.12.6 license: Apache-2.0 @@ -24504,6 +24444,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/storage-compat +0.3.8 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/storage-compat 0.3.9 license: Apache-2.0 @@ -24518,6 +24465,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/util +1.9.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/util 1.9.7 license: Apache-2.0 @@ -24525,6 +24479,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/vertexai-preview +0.0.2 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/vertexai-preview 0.0.3 license: Apache-2.0 @@ -24532,6 +24493,13 @@ authors: Firebase (https://firebase.google.com/) ****************************** +@firebase/webchannel-wrapper +1.0.0 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + @firebase/webchannel-wrapper 1.0.1 license: Apache-2.0 @@ -31142,34 +31110,6 @@ This library is a fork of 'better-json-errors' by Kat Marchán, extended and distributed under the terms of the MIT license above. -****************************** - -jsonpath-plus -7.2.0 -The MIT License (MIT) - -Copyright (c) 2011-2019 Stefan Goessner, Subbu Allamaraju, Mike Brevoort, -Robert Krahn, Brett Zamir, Richard Schneider - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ****************************** json-pointer @@ -35487,14 +35427,14 @@ authors: Egor Gumenyuk ****************************** @metamask/abi-utils -2.0.2 +2.0.4 license: (Apache-2.0 AND MIT) authors: Maarten Zuidhoorn ****************************** @metamask/accounts-controller -18.1.0 +18.2.1 MIT License Copyright (c) 2018 MetaMask @@ -35520,7 +35460,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/address-book-controller -4.0.1 +6.0.1 MIT License Copyright (c) 2018 MetaMask @@ -35546,33 +35486,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/approval-controller -6.0.2 -MIT License - -Copyright (c) 2018 MetaMask - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - - -****************************** - -@metamask/approval-controller -7.0.2 +7.1.0 MIT License Copyright (c) 2018 MetaMask @@ -35598,7 +35512,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/assets-controllers -30.0.0 +36.0.0 MIT License Copyright (c) 2018 MetaMask @@ -35753,55 +35667,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** -@metamask/browser-passworder -4.3.0 -ISC License - -Copyright (c) 2020 MetaMask - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -****************************** - -@metamask/composable-controller -3.0.3 -MIT License - -Copyright (c) 2018 MetaMask - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - - -****************************** - -@metamask/contract-metadata -2.2.0 +@metamask/browser-passworder +4.3.0 ISC License Copyright (c) 2020 MetaMask @@ -35821,8 +35688,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** -@metamask/controller-utils -10.0.0 +@metamask/composable-controller +3.0.3 MIT License Copyright (c) 2018 MetaMask @@ -35845,10 +35712,31 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +****************************** + +@metamask/contract-metadata +2.2.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ****************************** @metamask/controller-utils -11.0.2 +11.3.0 MIT License Copyright (c) 2018 MetaMask @@ -35930,6 +35818,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE license: MIT authors: undefined +****************************** + +@metamask/eth-block-tracker +10.1.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + ****************************** @metamask/eth-block-tracker @@ -35980,7 +35894,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/eth-hd-keyring -7.0.1 +7.0.4 ISC License Copyright (c) 2020 MetaMask @@ -36121,6 +36035,27 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +****************************** + +@metamask/eth-json-rpc-middleware +13.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ****************************** @metamask/eth-json-rpc-provider @@ -36173,7 +36108,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/eth-json-rpc-provider -4.1.3 +4.1.4 ISC License Copyright (c) 2022 MetaMask @@ -36357,7 +36292,7 @@ authors: undefined ****************************** @metamask/eth-sig-util -7.0.2 +7.0.3 ISC License Copyright (c) 2020 MetaMask @@ -36377,8 +36312,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** -@metamask/eth-simple-keyring -6.0.1 +@metamask/eth-sig-util +8.0.0 ISC License Copyright (c) 2020 MetaMask @@ -36398,41 +36333,36 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** -@metamask/eth-snap-keyring -4.3.1 -license: Custom: https://metamask.github.io/eth-snap-keyring/latest/ -authors: undefined - -****************************** +@metamask/eth-simple-keyring +6.0.5 +ISC License -@metamask/gas-fee-controller -12.0.0 -MIT License +Copyright (c) 2020 MetaMask -Copyright (c) 2018 MetaMask +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +****************************** +@metamask/eth-snap-keyring +4.3.4 +license: Custom: https://metamask.github.io/eth-snap-keyring/latest/ +authors: undefined ****************************** @metamask/gas-fee-controller -18.0.0 +12.0.0 MIT License Copyright (c) 2018 MetaMask @@ -36458,7 +36388,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/gas-fee-controller -19.0.0 +18.0.0 MIT License Copyright (c) 2018 MetaMask @@ -36526,7 +36456,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/json-rpc-engine -9.0.2 +9.0.3 ISC License Copyright (c) 2022 MetaMask @@ -36589,21 +36519,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/keyring-api -6.4.0 -license: Custom: https://docs.metamask.io/snaps/ -authors: undefined - -****************************** - -@metamask/keyring-api -8.1.0 +8.1.3 license: Custom: https://docs.metamask.io/snaps/ authors: undefined ****************************** @metamask/keyring-controller -16.1.0 +17.2.2 MIT License Copyright (c) 2018 MetaMask @@ -36656,21 +36579,14 @@ SOFTWARE. ****************************** @metamask/logging-controller -3.0.1 -license: MIT -authors: undefined - -****************************** - -@metamask/logging-controller -4.0.0 +6.0.1 license: MIT authors: undefined ****************************** @metamask/message-manager -9.0.0 +10.1.1 MIT License Copyright (c) 2018 MetaMask @@ -36749,7 +36665,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/network-controller -18.1.3 +19.0.0 MIT License Copyright (c) 2018 MetaMask @@ -36775,7 +36691,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/network-controller -19.0.0 +20.1.0 MIT License Copyright (c) 2018 MetaMask @@ -36801,7 +36717,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/network-controller -20.1.0 +21.0.1 MIT License Copyright (c) 2018 MetaMask @@ -36851,10 +36767,37 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@metamask/nonce-tracker +6.0.0 +MIT License + +Copyright (c) 2019 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ****************************** @metamask/notification-services-controller -0.2.1 +0.8.2 MIT License Copyright (c) 2024 MetaMask @@ -37019,36 +36962,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -****************************** - -@metamask/permission-controller -9.1.1 -MIT License - -Copyright (c) 2018 MetaMask - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - - ****************************** @metamask/phishing-controller -10.1.1 +12.0.3 MIT License Copyright (c) 2018 MetaMask @@ -37073,8 +36990,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** -@metamask/phishing-controller -9.0.2 +@metamask/polling-controller +4.0.0 MIT License Copyright (c) 2018 MetaMask @@ -37100,7 +37017,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/polling-controller -4.0.0 +8.0.0 MIT License Copyright (c) 2018 MetaMask @@ -37126,7 +37043,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/polling-controller -6.0.2 +9.0.1 MIT License Copyright (c) 2018 MetaMask @@ -37151,34 +37068,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** -@metamask/polling-controller -8.0.0 -MIT License +@metamask/post-message-stream +8.1.1 +ISC License -Copyright (c) 2018 MetaMask +Copyright (c) 2020 MetaMask -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +****************************** + +@metamask/ppom-validator +0.32.0 +license: Custom: https://nodejs.org +authors: undefined ****************************** -@metamask/polling-controller -9.0.0 +@metamask/preferences-controller +11.0.0 MIT License Copyright (c) 2018 MetaMask @@ -37201,38 +37120,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -****************************** - -@metamask/post-message-stream -8.1.0 -ISC License - -Copyright (c) 2020 MetaMask - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -****************************** - -@metamask/ppom-validator -0.32.0 -license: Custom: https://nodejs.org -authors: undefined - ****************************** @metamask/preferences-controller -11.0.0 +13.0.3 MIT License Copyright (c) 2018 MetaMask @@ -37258,7 +37149,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/profile-sync-controller -0.2.1 +0.9.7 MIT License Copyright (c) 2024 MetaMask @@ -37424,37 +37315,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -@metamask/react-native-splash-screen -3.2.0 -MIT License - -Copyright (c) 2016 Jia PengHui - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ****************************** @metamask/react-native-webview -14.0.3 +14.0.4 MIT License Copyright (c) 2015-present, Facebook, Inc. @@ -37627,7 +37491,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/signature-controller -17.0.0 +20.1.0 MIT License Copyright (c) 2023 MetaMask @@ -37667,7 +37531,7 @@ authors: Dan Finlay ****************************** @metamask/smart-transactions-controller -11.0.0 +13.0.0 Copyright ConsenSys Software Inc. 2020. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -37691,31 +37555,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-controllers -8.3.1 -Copyright ConsenSys Software Inc. 2021. All rights reserved. - -You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. - -Subject to the limited license below, you may not (and you may not permit anyone else to) distribute, publish, copy, modify, merge, combine with another program, create derivative works of, reverse engineer, decompile or otherwise attempt to extract the source code of, the Program or any part thereof, except that you may contribute to this repository. - -You are granted a non-exclusive, non-transferable, non-sublicensable license to distribute, publish, copy, modify, merge, combine with another program or create derivative works of the Program (such resulting program, collectively, the “Resulting Program”) solely for Non-Commercial Use as long as you: - 1. give prominent notice (“Notice”) with each copy of the Resulting Program that the Program is used in the Resulting Program and that the Program is the copyright of ConsenSys; and - 2. subject the Resulting Program and any distribution, publication, copy, modification, merger therewith, combination with another program or derivative works thereof to the same Notice requirement and Non-Commercial Use restriction set forth herein. - -“Non-Commercial Use” means each use as described in clauses (1)-(3) below, as reasonably determined by ConsenSys in its sole discretion: - 1. personal use for research, personal study, private entertainment, hobby projects or amateur pursuits, in each case without any anticipated commercial application; - 2. use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization or government institution; or - 3. the number of monthly active users of the Resulting Program across all versions thereof and platforms globally do not exceed 10,000 at any time. - -You will not use any trade mark, service mark, trade name, logo of ConsenSys or any other company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos. - -If you have any questions, comments or interest in pursuing any other use cases, please reach out to us at metamask.license@consensys.net. - - -****************************** - -@metamask/snaps-controllers -9.4.0 +9.8.0 Copyright ConsenSys Software Inc. 2021. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -37739,7 +37579,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-execution-environments -6.6.2 +6.7.2 Copyright ConsenSys Software Inc. 2022. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -37972,7 +37812,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-rpc-methods -11.0.0 +11.1.1 Copyright ConsenSys Software Inc. 2021. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -38041,28 +37881,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/snaps-sdk -4.4.1 -ISC License - -Copyright (c) 2023 MetaMask - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -****************************** - -@metamask/snaps-sdk -6.2.1 +6.5.1 ISC License Copyright (c) 2023 MetaMask @@ -38104,7 +37923,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/snaps-utils -8.0.1 +8.1.1 ISC License Copyright (c) 2022 MetaMask @@ -38122,6 +37941,13 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +****************************** + +@metamask/stake-sdk +0.2.13 +license: Custom: https://nodejs.org +authors: undefined + ****************************** @metamask/superstruct @@ -38180,7 +38006,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/transaction-controller -35.0.0 +37.1.0 MIT License Copyright (c) 2018 MetaMask @@ -38248,7 +38074,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/utils -9.1.0 +9.2.1 ISC License Copyright (c) 2022 MetaMask @@ -39903,6 +39729,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ****************************** +node-addon-api +5.1.0 +The MIT License (MIT) +===================== + +Copyright (c) 2017 Node.js API collaborators +----------------------------------- + +*Node.js API collaborators listed at * + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + node-addon-api 6.1.0 The MIT License (MIT) @@ -40747,41 +40591,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -normalize-svg-path -1.1.0 - -The MIT License - -Copyright © 2008-2013 Dmitry Baranovskiy (http://raphaeljs.com) -Copyright © 2008-2013 Sencha Labs (http://sencha.com) -Copyright © 2013 Jake Rosoman - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - ****************************** @notifee/react-native -7.8.2 +9.0.2 Apache-2.0 License ------------------ @@ -41163,13 +40976,6 @@ SOFTWARE. -****************************** - -obs-store -4.0.3 -license: ISC -authors: undefined - ****************************** octal @@ -41643,35 +41449,6 @@ parse-multipart-data license: MIT authors: Ignacio Mazzara (nachomazzara@gmail.com) -****************************** - -parse-svg-path -0.1.2 - -The MIT License - -Copyright (c) 2013 Jake Rosoman - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - ****************************** parseurl @@ -45767,8 +45544,15 @@ authors: Brent Vatne ****************************** +react-native-fast-crypto +2.2.0 +license: MIT +authors: Edge + +****************************** + @react-native-firebase/app -20.1.0 +20.5.0 Apache-2.0 License ------------------ @@ -45806,7 +45590,7 @@ You may obtain a copy of the Creative Commons Attribution 3.0 License at ****************************** @react-native-firebase/messaging -20.1.0 +20.5.0 Apache-2.0 License ------------------ @@ -45841,33 +45625,6 @@ You may obtain a copy of the Creative Commons Attribution 3.0 License at https://creativecommons.org/licenses/by/3.0/ -****************************** - -react-native-flash-message -0.1.11 -MIT License - -Copyright (c) 2018 Lucas Ferreira - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ****************************** react-native-fs @@ -46574,33 +46331,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -@react-native-picker/picker -2.2.1 -MIT License - -Copyright (c) 2015-present, Facebook, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ****************************** react-native-progress @@ -46685,99 +46415,72 @@ SOFTWARE. ****************************** -react-native-quick-crypto -0.6.1 -**react-native-quick-crypto** - -MIT License - -Copyright (c) 2021 Margelo GmbH - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -**NodeJS Crypto** - -See https://github.com/nodejs/node/blob/main/LICENSE - - -****************************** - -react-native-randombytes -3.6.1 -The MIT License (MIT) - -Copyright (c) 2015 Mark Vayngrib - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - -****************************** - -react-native-reanimated -3.4.2 -The MIT License (MIT) - -Copyright (c) 2016 Software Mansion - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -****************************** - -react-native-redash -16.2.2 +react-native-quick-crypto +0.6.1 +**react-native-quick-crypto** + MIT License -Copyright (c) 2020 William Candillon +Copyright (c) 2021 Margelo GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +**NodeJS Crypto** + +See https://github.com/nodejs/node/blob/main/LICENSE + + +****************************** + +react-native-randombytes +3.6.1 +The MIT License (MIT) + +Copyright (c) 2015 Mark Vayngrib + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +react-native-reanimated +3.4.2 +The MIT License (MIT) + +Copyright (c) 2016 Software Mansion Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -49294,6 +48997,33 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +reselect +5.1.1 +The MIT License (MIT) + +Copyright (c) 2015-2018 Reselect Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ****************************** resolve @@ -49488,6 +49218,21 @@ SOFTWARE. +****************************** + +rfc4648 +1.5.3 +The MIT License (MIT) + +Copyright © 2022 William R Swanson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ****************************** rfdc @@ -50357,33 +50102,6 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice defined by the Mozilla Public License, v. 2.0. -****************************** - -@rnhooks/keyboard -0.0.3 -MIT License - -Copyright (c) 2019 React Native Hooks - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ****************************** run-parallel @@ -51222,7 +50940,7 @@ THE SOFTWARE. ****************************** secp256k1 -3.8.0 +3.8.1 The MIT License (MIT) Copyright (c) 2014-2016 secp256k1-node contributors @@ -51252,7 +50970,7 @@ THE SOFTWARE. ****************************** secp256k1 -4.0.3 +4.0.4 The MIT License (MIT) Copyright (c) 2014-2016 secp256k1-node contributors @@ -51539,7 +51257,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************** @sentry/browser -7.119.0 +7.119.1 Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -51559,7 +51277,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ****************************** @sentry/cli -2.36.1 +2.36.6 Copyright (c) 2016 Sentry (https://sentry.io/) and individual contributors. All rights reserved. @@ -51592,7 +51310,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************** @sentry/cli-darwin -2.36.1 +2.36.6 license: BSD-3-Clause authors: undefined @@ -51616,6 +51334,26 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER I OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@sentry/core +7.119.1 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ****************************** @sentry/hub @@ -51691,10 +51429,30 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER I OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@sentry/integrations +7.119.1 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ****************************** @sentry-internal/feedback -7.119.0 +7.119.1 Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -51714,7 +51472,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ****************************** @sentry-internal/replay-canvas -7.119.0 +7.119.1 Copyright (c) 2024 Sentry (https://sentry.io) and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -51734,7 +51492,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ****************************** @sentry-internal/tracing -7.119.0 +7.119.1 Copyright (c) 2020 Sentry (https://sentry.io) and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -51754,7 +51512,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ****************************** @sentry/react -7.119.0 +7.119.1 Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -51774,7 +51532,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ****************************** @sentry/react-native -5.33.0 +5.33.2 The MIT License (MIT) Copyright (c) 2017-2024 Sentry @@ -51801,7 +51559,7 @@ SOFTWARE. ****************************** @sentry/replay -7.119.0 +7.119.1 Copyright (c) 2022 Sentry (https://sentry.io) and individual contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -51873,6 +51631,26 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER I OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@sentry/types +7.119.1 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ****************************** @sentry/utils @@ -51928,6 +51706,26 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER I OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@sentry/utils +7.119.1 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ****************************** serialize-error @@ -94637,28 +94435,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -svg-arc-to-cubic-bezier -3.2.0 -Internet Systems Consortium license -=================================== - -Copyright (c) `2017`, `Colin Meinke` - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - - ****************************** symbol-observable @@ -95765,36 +95541,6 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************** - -traverse -0.6.6 -Copyright 2010 James Halliday (mail@substack.net) - -This project is free software released under the MIT/X11 license: -http://www.opensource.org/licenses/mit-license.php - -Copyright 2010 James Halliday (mail@substack.net) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - ****************************** truncate-utf8-bytes @@ -102815,25 +102561,6 @@ POSSIBILITY OF SUCH DAMAGE. -****************************** - -weak -1.0.1 -Copyright (c) 2011, Ben Noordhuis - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ****************************** webextension-polyfill diff --git a/bitrise.yml b/bitrise.yml index 0cbeb6d0b66..7e69d7cabad 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -1536,16 +1536,16 @@ app: PROJECT_LOCATION_IOS: ios - opts: is_expand: false - VERSION_NAME: 7.32.0 + VERSION_NAME: 7.33.0 - opts: is_expand: false - VERSION_NUMBER: 1450 + VERSION_NUMBER: 1460 - opts: is_expand: false - FLASK_VERSION_NAME: 7.32.0 + FLASK_VERSION_NAME: 7.33.0 - opts: is_expand: false - FLASK_VERSION_NUMBER: 1450 + FLASK_VERSION_NUMBER: 1460 - opts: is_expand: false ANDROID_APK_LINK: '' diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index 314bc34f316..43068635fab 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -1273,7 +1273,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1450; + CURRENT_PROJECT_VERSION = 1460; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1310,7 +1310,7 @@ "${inherited}", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.32.0; + MARKETING_VERSION = 7.33.0; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1338,7 +1338,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1450; + CURRENT_PROJECT_VERSION = 1460; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1373,7 +1373,7 @@ "${inherited}", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.32.0; + MARKETING_VERSION = 7.33.0; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1401,7 +1401,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1450; + CURRENT_PROJECT_VERSION = 1460; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1434,7 +1434,7 @@ ); LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)"; LLVM_LTO = YES; - MARKETING_VERSION = 7.32.0; + MARKETING_VERSION = 7.33.0; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1462,7 +1462,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1450; + CURRENT_PROJECT_VERSION = 1460; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1493,7 +1493,7 @@ ); LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)"; LLVM_LTO = YES; - MARKETING_VERSION = 7.32.0; + MARKETING_VERSION = 7.33.0; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -1616,7 +1616,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1450; + CURRENT_PROJECT_VERSION = 1460; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1653,7 +1653,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.32.0; + MARKETING_VERSION = 7.33.0; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "$(inherited)", @@ -1684,7 +1684,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1450; + CURRENT_PROJECT_VERSION = 1460; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1719,7 +1719,7 @@ "\"$(SRCROOT)/MetaMask/System/Library/Frameworks\"", ); LLVM_LTO = YES; - MARKETING_VERSION = 7.32.0; + MARKETING_VERSION = 7.33.0; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", diff --git a/package.json b/package.json index 382238a403b..b4654218bf6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask", - "version": "7.32.0", + "version": "7.33.0", "private": true, "scripts": { "audit:ci": "./scripts/yarn-audit.sh", From 9b8599ec175c1691545e9b99b0d090e0089d21b0 Mon Sep 17 00:00:00 2001 From: Nico MASSART Date: Fri, 25 Oct 2024 20:39:56 +0200 Subject: [PATCH 03/90] fix: migrate from decommissioned ipfs gateway to new one (#11985) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - adds state migration for users with decommissioned IPFS gateway - adds migration tests - adds new target gateway (dweb.link) to list and make it replace decommissioned gateway. >[!NOTE] > this is only a state migration, the user will not have any visible warnings. It will only show the new gateway as selected instead of the decommissioned one if it was in their state. ## **Related issues** Fixes #11692 ## **Manual testing steps** ```gherkin Feature: Migrate from decommissioned gateway to dweb.link Scenario: Verify non migrated gateway Given an installed app that was built before the decommission of https://cloudflare-ipfs.com/ipfs/ (pre ac7978596566f148fa6892940fb5678170ba0351, for latest is 7.32.0) When go to security & privacy settings And select https://cloudflare-ipfs.com/ipfs/ Then see "Your current IPFS gateway is down" as decommissioned gateway does not respond Scenario: Check migration Given the current PR app installed When go to security & privacy settings Then see "https://dweb.link/ipfs/" gateway selected ``` ## **Screenshots/Recordings** ### **Before** Simulator Screenshot - iPhone 16 Pro - 2024-10-23 at 22 00 21 ### **After** Simulator Screenshot - iPhone 16 Pro - 2024-10-23 at 22 15 31 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com> --- .../Base/RemoteImage/index.test.tsx | 2 +- app/components/UI/AssetIcon/index.test.tsx | 4 +- .../UI/Swaps/components/TokenIcon.test.js | 4 +- .../components/TokenSelectButton.test.js | 4 +- .../__snapshots__/TokenIcon.test.js.snap | 4 +- .../TokenSelectButton.test.js.snap | 4 +- .../Views/confirmations/Send/index.test.tsx | 2 +- app/constants/network.js | 2 +- app/core/AppConstants.ts | 2 +- app/store/migrations/056.test.ts | 119 ++++++++++++++++++ app/store/migrations/056.ts | 31 +++++ app/store/migrations/index.ts | 2 + app/util/ipfs-gateways.json | 5 + app/util/sentry/utils.test.ts | 2 +- app/util/test/initial-background-state.json | 2 +- e2e/fixtures/fixture-builder.js | 4 +- 16 files changed, 175 insertions(+), 18 deletions(-) create mode 100644 app/store/migrations/056.test.ts create mode 100644 app/store/migrations/056.ts diff --git a/app/components/Base/RemoteImage/index.test.tsx b/app/components/Base/RemoteImage/index.test.tsx index 429dfeb7ca5..65691852ebe 100644 --- a/app/components/Base/RemoteImage/index.test.tsx +++ b/app/components/Base/RemoteImage/index.test.tsx @@ -6,7 +6,7 @@ jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), useSelector: jest .fn() - .mockImplementation(() => 'https://gateway.pinata.cloud/ipfs/'), + .mockImplementation(() => 'https://dweb.link/ipfs/'), })); jest.mock('../../../components/hooks/useIpfsGateway', () => jest.fn()); diff --git a/app/components/UI/AssetIcon/index.test.tsx b/app/components/UI/AssetIcon/index.test.tsx index 84c0941722a..b6541f8ffa8 100644 --- a/app/components/UI/AssetIcon/index.test.tsx +++ b/app/components/UI/AssetIcon/index.test.tsx @@ -10,7 +10,7 @@ const mockInitialState = { ...backgroundState, PreferencesController: { featureFlags: {}, - ipfsGateway: 'https://gateway.pinata.cloud/ipfs/', + ipfsGateway: 'https://dweb.link/ipfs/', lostIdentities: {}, selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3', useTokenDetection: true, @@ -25,7 +25,7 @@ const mockInitialState = { _W: { featureFlags: {}, frequentRpcList: [], - ipfsGateway: 'https://gateway.pinata.cloud/ipfs/', + ipfsGateway: 'https://dweb.link/ipfs/', lostIdentities: {}, selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3', useTokenDetection: true, diff --git a/app/components/UI/Swaps/components/TokenIcon.test.js b/app/components/UI/Swaps/components/TokenIcon.test.js index f8f0bc4adb3..476343f4329 100644 --- a/app/components/UI/Swaps/components/TokenIcon.test.js +++ b/app/components/UI/Swaps/components/TokenIcon.test.js @@ -13,7 +13,7 @@ describe('TokenIcon component', () => { const icon = shallow( , ); expect(icon).toMatchSnapshot(); @@ -27,7 +27,7 @@ describe('TokenIcon component', () => { , ); expect(iconMedium).toMatchSnapshot(); diff --git a/app/components/UI/Swaps/components/TokenSelectButton.test.js b/app/components/UI/Swaps/components/TokenSelectButton.test.js index 328501a798a..376f482d497 100644 --- a/app/components/UI/Swaps/components/TokenSelectButton.test.js +++ b/app/components/UI/Swaps/components/TokenSelectButton.test.js @@ -19,7 +19,7 @@ describe('TokenSelectButton component', () => { , ); expect(icon).toMatchSnapshot(); @@ -27,7 +27,7 @@ describe('TokenSelectButton component', () => { , ); diff --git a/app/components/UI/Swaps/components/__snapshots__/TokenIcon.test.js.snap b/app/components/UI/Swaps/components/__snapshots__/TokenIcon.test.js.snap index 8b00e7564fd..3ebab929b29 100644 --- a/app/components/UI/Swaps/components/__snapshots__/TokenIcon.test.js.snap +++ b/app/components/UI/Swaps/components/__snapshots__/TokenIcon.test.js.snap @@ -57,7 +57,7 @@ exports[`TokenIcon component should Render correctly 4`] = ` onError={[Function]} source={ { - "uri": "https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ", + "uri": "https://dweb.link/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ", } } style={ @@ -146,7 +146,7 @@ exports[`TokenIcon component should Render correctly 8`] = ` onError={[Function]} source={ { - "uri": "https://gateway.pinata.cloud/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ", + "uri": "https://dweb.link/ipfs/QmNYVMm3iC7HEoxfvxsZbRoapdjDHj9EREFac4BPeVphSJ", } } style={ diff --git a/app/components/UI/Swaps/components/__snapshots__/TokenSelectButton.test.js.snap b/app/components/UI/Swaps/components/__snapshots__/TokenSelectButton.test.js.snap index 8c6472bfbac..1c01f4d06e1 100644 --- a/app/components/UI/Swaps/components/__snapshots__/TokenSelectButton.test.js.snap +++ b/app/components/UI/Swaps/components/__snapshots__/TokenSelectButton.test.js.snap @@ -71,7 +71,7 @@ exports[`TokenSelectButton component should Render correctly 4`] = ` } > @@ -95,7 +95,7 @@ exports[`TokenSelectButton component should Render correctly 5`] = ` } > diff --git a/app/components/Views/confirmations/Send/index.test.tsx b/app/components/Views/confirmations/Send/index.test.tsx index a1d650918ef..297c420cb78 100644 --- a/app/components/Views/confirmations/Send/index.test.tsx +++ b/app/components/Views/confirmations/Send/index.test.tsx @@ -65,7 +65,7 @@ const initialState: DeepPartial = { }, PreferencesController: { featureFlags: {}, - ipfsGateway: 'https://gateway.pinata.cloud/ipfs/', + ipfsGateway: 'https://dweb.link/ipfs/', lostIdentities: {}, selectedAddress: MOCK_ADDRESS_2, useTokenDetection: true, diff --git a/app/constants/network.js b/app/constants/network.js index 5a804714de8..90e7925de06 100644 --- a/app/constants/network.js +++ b/app/constants/network.js @@ -11,7 +11,7 @@ export const RPC = NetworkType.rpc; export const NO_RPC_BLOCK_EXPLORER = 'NO_BLOCK_EXPLORER'; export const PRIVATENETWORK = 'PRIVATENETWORK'; export const DEFAULT_MAINNET_CUSTOM_NAME = 'Ethereum Main Custom'; -export const IPFS_DEFAULT_GATEWAY_URL = 'https://gateway.pinata.cloud/ipfs/'; +export const IPFS_DEFAULT_GATEWAY_URL = 'https://dweb.link/ipfs/'; /** * @enum {string} diff --git a/app/core/AppConstants.ts b/app/core/AppConstants.ts index 8aea9a7cb72..85d04769bcf 100644 --- a/app/core/AppConstants.ts +++ b/app/core/AppConstants.ts @@ -12,7 +12,7 @@ export default { DEFAULT_SEARCH_ENGINE: 'DuckDuckGo', TX_CHECK_BACKGROUND_FREQUENCY: 30000, IPFS_OVERRIDE_PARAM: 'mm_override', - IPFS_DEFAULT_GATEWAY_URL: 'https://gateway.pinata.cloud/ipfs/', + IPFS_DEFAULT_GATEWAY_URL: 'https://dweb.link/ipfs/', IPNS_DEFAULT_GATEWAY_URL: 'https://gateway.pinata.cloud/ipns/', SWARM_DEFAULT_GATEWAY_URL: 'https://swarm-gateways.net/bzz:/', supportedTLDs: ['eth', 'xyz', 'test'], diff --git a/app/store/migrations/056.test.ts b/app/store/migrations/056.test.ts new file mode 100644 index 00000000000..775de63d6f6 --- /dev/null +++ b/app/store/migrations/056.test.ts @@ -0,0 +1,119 @@ +import migrate from './056'; +import { merge } from 'lodash'; +import { captureException } from '@sentry/react-native'; +import initialRootState from '../../util/test/initial-root-state'; +import mockedEngine from '../../core/__mocks__/MockedEngine'; + +jest.mock('@sentry/react-native', () => ({ + captureException: jest.fn(), +})); +const mockedCaptureException = jest.mocked(captureException); + +jest.mock('../../core/Engine', () => ({ + init: () => mockedEngine.init(), +})); + +describe('Migration #56', () => { + beforeEach(() => { + jest.restoreAllMocks(); + jest.resetAllMocks(); + }); + + const invalidStates = [ + { + state: null, + errorMessage: "FATAL ERROR: Migration 56: Invalid state error: 'object'", + scenario: 'state is invalid', + }, + { + state: merge({}, initialRootState, { + engine: null, + }), + errorMessage: + "FATAL ERROR: Migration 56: Invalid engine state error: 'object'", + scenario: 'engine state is invalid', + }, + { + state: merge({}, initialRootState, { + engine: { + backgroundState: null, + }, + }), + errorMessage: + "FATAL ERROR: Migration 56: Invalid engine backgroundState error: 'object'", + scenario: 'backgroundState is invalid', + }, + { + state: merge({}, initialRootState, { + engine: { + backgroundState: { PreferencesController: null }, + }, + }), + errorMessage: + "FATAL ERROR: Migration 56: Invalid PreferencesController state error: 'object'", + scenario: 'PreferencesController is invalid', + }, + ]; + + for (const { errorMessage, scenario, state } of invalidStates) { + it(`should capture exception if ${scenario}`, () => { + const newState = migrate(state); + + expect(newState).toStrictEqual(state); + expect(mockedCaptureException).toHaveBeenCalledWith(expect.any(Error)); + expect(mockedCaptureException.mock.calls[0][0].message).toBe( + errorMessage, + ); + }); + } + + it('updates decomissioned ipfsGateway to new default', () => { + const oldState = { + engine: { + backgroundState: { + PreferencesController: { + ipfsGateway: 'https://cloudflare-ipfs.com/ipfs/', + }, + }, + }, + }; + + const expectedState = { + engine: { + backgroundState: { + PreferencesController: { + ipfsGateway: 'https://dweb.link/ipfs/', + }, + }, + }, + }; + + const migratedState = migrate(oldState); + expect(migratedState).toStrictEqual(expectedState); + }); + + it('does not change ipfsGateway if not decomissioned', () => { + const oldState = { + engine: { + backgroundState: { + PreferencesController: { + ipfsGateway: 'https://ipfs.io/ipfs/', + }, + }, + }, + }; + + const expectedState = { + engine: { + backgroundState: { + PreferencesController: { + ipfsGateway: 'https://ipfs.io/ipfs/', + }, + }, + }, + }; + + const migratedState = migrate(oldState); + expect(migratedState).toStrictEqual(expectedState); + }); +}); diff --git a/app/store/migrations/056.ts b/app/store/migrations/056.ts new file mode 100644 index 00000000000..df29f5ba5e6 --- /dev/null +++ b/app/store/migrations/056.ts @@ -0,0 +1,31 @@ +import { captureException } from '@sentry/react-native'; +import { isObject } from '@metamask/utils'; +import { ensureValidState } from './util'; + +export default function migrate(state: unknown) { + if (!ensureValidState(state, 56)) { + // Increment the migration number as appropriate + return state; + } + + const preferencesController = + state.engine.backgroundState.PreferencesController; + + if (!isObject(preferencesController)) { + captureException( + new Error( + `FATAL ERROR: Migration 56: Invalid PreferencesController state error: '${typeof preferencesController}'`, + ), + ); + return state; + } + + const decommisionedIpfsGateway = 'https://cloudflare-ipfs.com/ipfs/'; + const newDefaultIpfsGateway = 'https://dweb.link/ipfs/'; + + if (decommisionedIpfsGateway === preferencesController?.ipfsGateway) { + preferencesController.ipfsGateway = newDefaultIpfsGateway; + } + // Return the modified state + return state; +} diff --git a/app/store/migrations/index.ts b/app/store/migrations/index.ts index c767d71edf6..4f8e9e30ee9 100644 --- a/app/store/migrations/index.ts +++ b/app/store/migrations/index.ts @@ -56,6 +56,7 @@ import migration52 from './052'; import migration53 from './053'; import migration54 from './054'; import migration55 from './055'; +import migration56 from './056'; type MigrationFunction = (state: unknown) => unknown; type AsyncMigrationFunction = (state: unknown) => Promise; @@ -124,6 +125,7 @@ export const migrationList: MigrationsList = { 53: migration53, 54: migration54, 55: migration55, + 56: migration56, }; // Enable both synchronous and asynchronous migrations diff --git a/app/util/ipfs-gateways.json b/app/util/ipfs-gateways.json index 20e6d4f8b11..7e4d103f836 100644 --- a/app/util/ipfs-gateways.json +++ b/app/util/ipfs-gateways.json @@ -18,5 +18,10 @@ "value": "https://gateway.pinata.cloud/ipfs/", "key": 24, "label": "https://gateway.pinata.cloud/ipfs/" + }, + { + "value": "https://dweb.link/ipfs/", + "key": 30, + "label": "https://dweb.link/ipfs/" } ] diff --git a/app/util/sentry/utils.test.ts b/app/util/sentry/utils.test.ts index a80ca2868f7..34486095c9f 100644 --- a/app/util/sentry/utils.test.ts +++ b/app/util/sentry/utils.test.ts @@ -252,7 +252,7 @@ describe('captureSentryFeedback', () => { name: 'Account 1', }, }, - ipfsGateway: 'https://gateway.pinata.cloud/ipfs/', + ipfsGateway: 'https://dweb.link/ipfs/', isIpfsGatewayEnabled: true, isMultiAccountBalancesEnabled: true, lostIdentities: {}, diff --git a/app/util/test/initial-background-state.json b/app/util/test/initial-background-state.json index 87e02448df0..529ccf1750b 100644 --- a/app/util/test/initial-background-state.json +++ b/app/util/test/initial-background-state.json @@ -156,7 +156,7 @@ "PreferencesController": { "featureFlags": {}, "identities": {}, - "ipfsGateway": "https://gateway.pinata.cloud/ipfs/", + "ipfsGateway": "https://dweb.link/ipfs/", "lostIdentities": {}, "selectedAddress": "", "useTokenDetection": true, diff --git a/e2e/fixtures/fixture-builder.js b/e2e/fixtures/fixture-builder.js index b850fab5970..553cc1882b7 100644 --- a/e2e/fixtures/fixture-builder.js +++ b/e2e/fixtures/fixture-builder.js @@ -277,7 +277,7 @@ class FixtureBuilder { importTime: 1684232000456, }, }, - ipfsGateway: 'https://gateway.pinata.cloud/ipfs/', + ipfsGateway: 'https://dweb.link/ipfs/', lostIdentities: {}, selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3', useTokenDetection: true, @@ -298,7 +298,7 @@ class FixtureBuilder { importTime: 1684232000456, }, }, - ipfsGateway: 'https://gateway.pinata.cloud/ipfs/', + ipfsGateway: 'https://dweb.link/ipfs/', lostIdentities: {}, selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3', useTokenDetection: true, From e7595b2fd632a723c87e0497922953b48648b853 Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Mon, 28 Oct 2024 09:58:13 +0100 Subject: [PATCH 04/90] feat: add new default networks (#11926) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR ensures that a predefined list of popular networks (Arbitrum, BSC, Base, Optimism, and Polygon) is automatically added for new users only during the app startup process. The networks are added using NetworkController.addNetwork within the useEffect hook inside the app's initialization flow. ## **Related issues** Fixes: ## **Manual testing steps** 1. Do a new fresh install app 2. Import/create your wallet 3. check the list of added networks ## **Screenshots/Recordings** ### **Before** ![Screenshot 2024-10-21 at 20 02 38](https://github.com/user-attachments/assets/c24f3a63-a315-4cb7-99f3-43a49ba0756f) ### **After** ![Screenshot 2024-10-21 at 19 56 59](https://github.com/user-attachments/assets/e5e785a2-374c-4f94-85d2-249cabede8a2) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/components/Nav/App/index.js | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index dbed500c1a1..82d6268f1ed 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -131,6 +131,10 @@ import OptionsSheet from '../../UI/SelectOptionSheet/OptionsSheet'; import FoxLoader from '../../../components/UI/FoxLoader'; import { AppStateEventProcessor } from '../../../core/AppStateEventListener'; import MultiRpcModal from '../../../components/Views/MultiRpcModal/MultiRpcModal'; +import Engine from '../../../core/Engine'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import { PopularList } from '../../../util/networks/customNetworks'; +import { RpcEndpointType } from '@metamask/network-controller'; import { trace, TraceName, TraceOperation } from '../../../util/trace'; const clearStackNavigatorOptions = { @@ -762,6 +766,46 @@ const App = (props) => { useEffect(() => { async function startApp() { const existingUser = await StorageWrapper.getItem(EXISTING_USER); + if (!existingUser) { + // List of chainIds to add (as hex strings) + const chainIdsToAdd = [ + CHAIN_IDS.ARBITRUM, + CHAIN_IDS.BASE, + CHAIN_IDS.BSC, + CHAIN_IDS.OPTIMISM, + CHAIN_IDS.POLYGON, + ]; + + // Filter the PopularList to get only the specified networks based on chainId + const selectedNetworks = PopularList.filter((network) => + chainIdsToAdd.includes(network.chainId), + ); + const { NetworkController } = Engine.context; + + // Loop through each selected network and call NetworkController.addNetwork + for (const network of selectedNetworks) { + try { + await NetworkController.addNetwork({ + chainId: network.chainId, + blockExplorerUrls: [network.rpcPrefs.blockExplorerUrl], + defaultRpcEndpointIndex: 0, + defaultBlockExplorerUrlIndex: 0, + name: network.nickname, + nativeCurrency: network.ticker, + rpcEndpoints: [ + { + url: network.rpcUrl, + name: network.nickname, + type: RpcEndpointType.Custom, + }, + ], + }); + } catch (error) { + Logger.error(error); + } + } + } + try { const currentVersion = getVersion(); const savedVersion = await StorageWrapper.getItem(CURRENT_APP_VERSION); From e958436bb7aae1f9f29b95163070d617e422718d Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:05:52 +0000 Subject: [PATCH 05/90] fix(deps): eth-json-rpc-middleware@4.3.0->9.0.1 (#12008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Update `eth-json-rpc-middleware` from `4.3.0` (2019-10-05) to `9.0.1` (2022-10-05). ## **Related issues** - Preparation for #11952 - #11978 #### Blocked by - [x] #11980 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .iyarc | 3 - app/core/BackgroundBridge/BackgroundBridge.js | 2 +- app/core/Snaps/SnapBridge.ts | 2 +- package.json | 2 +- yarn.lock | 388 +++--------------- 5 files changed, 62 insertions(+), 335 deletions(-) diff --git a/.iyarc b/.iyarc index abbf0e189d2..e69de29bb2d 100644 --- a/.iyarc +++ b/.iyarc @@ -1,3 +0,0 @@ -# ReDoS vulnerability, no impact to this application, and fix not backported yet to the versions we use - -GHSA-c2qf-rxjj-qqgw diff --git a/app/core/BackgroundBridge/BackgroundBridge.js b/app/core/BackgroundBridge/BackgroundBridge.js index 5051d77cbd5..78dd22aa8b7 100644 --- a/app/core/BackgroundBridge/BackgroundBridge.js +++ b/app/core/BackgroundBridge/BackgroundBridge.js @@ -28,7 +28,7 @@ import { SubjectType } from '@metamask/permission-controller'; const createFilterMiddleware = require('eth-json-rpc-filters'); const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager'); -const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware'); +const { providerAsMiddleware } = require('eth-json-rpc-middleware'); const pump = require('pump'); // eslint-disable-next-line import/no-nodejs-modules const EventEmitter = require('events').EventEmitter; diff --git a/app/core/Snaps/SnapBridge.ts b/app/core/Snaps/SnapBridge.ts index 5a9c468dc65..2ab13fbf5d0 100644 --- a/app/core/Snaps/SnapBridge.ts +++ b/app/core/Snaps/SnapBridge.ts @@ -24,7 +24,7 @@ import { SubjectType } from '@metamask/permission-controller'; const ObjectMultiplex = require('@metamask/object-multiplex'); const createFilterMiddleware = require('eth-json-rpc-filters'); const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager'); -const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware'); +const { providerAsMiddleware } = require('eth-json-rpc-middleware'); const pump = require('pump'); interface ISnapBridgeProps { diff --git a/package.json b/package.json index b4654218bf6..64c97bd6ba6 100644 --- a/package.json +++ b/package.json @@ -240,7 +240,7 @@ "eth-block-tracker": "^7.0.1", "eth-ens-namehash": "2.0.8", "eth-json-rpc-filters": "^6.0.1", - "eth-json-rpc-middleware": "4.3.0", + "eth-json-rpc-middleware": "9.0.1", "eth-url-parser": "1.0.4", "ethereumjs-abi": "0.6.6", "ethereumjs-util": "6.1.0", diff --git a/yarn.lock b/yarn.lock index d584a9bd090..eb76c4231d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1859,7 +1859,7 @@ "@ethereumjs/util" "^9.0.3" ethereum-cryptography "^2.1.3" -"@ethereumjs/util@^8.0.0", "@ethereumjs/util@^8.1.0": +"@ethereumjs/util@^8.0.0", "@ethereumjs/util@^8.0.6", "@ethereumjs/util@^8.1.0": version "8.1.0" resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== @@ -4630,6 +4630,18 @@ json-rpc-random-id "^1.0.0" xtend "^4.0.1" +"@metamask/eth-sig-util@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-5.1.0.tgz#a47f62800ee1917fef976ba67544a0ccd7d1bd6b" + integrity sha512-mlgziIHYlA9pi/XZerChqg4NocdOgBPB9NmxgXWQO2U2hH8RGOJQrz6j/AIKkYxgCMIE2PY000+joOwXfzeTDQ== + dependencies: + "@ethereumjs/util" "^8.0.6" + bn.js "^4.12.0" + ethereum-cryptography "^2.0.0" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + "@metamask/eth-sig-util@^7.0.0", "@metamask/eth-sig-util@^7.0.1", "@metamask/eth-sig-util@^7.0.2", "@metamask/eth-sig-util@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-7.0.3.tgz#be9e444fe0b8474c04e2ff42fd983173767f6ac0" @@ -5650,6 +5662,16 @@ lodash "^4.17.21" uuid "^8.3.2" +"@metamask/utils@^3.0.3": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-3.6.0.tgz#b218b969a05ca7a8093b5d1670f6625061de707d" + integrity sha512-9cIRrfkWvHblSiNDVXsjivqa9Ak0RYo/1H6tqTqTbAx+oBK2Sva0lWDHxGchOqA7bySGUJKAWSNJvH6gdHZ0gQ== + dependencies: + "@types/debug" "^4.1.7" + debug "^4.3.4" + semver "^7.3.8" + superstruct "^1.0.3" + "@metamask/utils@^5.0.1": version "5.0.2" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-5.0.2.tgz#140ba5061d90d9dac0280c19cab101bc18c8857c" @@ -9449,13 +9471,6 @@ dependencies: "@types/node" "*" -"@types/bn.js@^4.11.3": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - "@types/bn.js@^5.1.0", "@types/bn.js@^5.1.5": version "5.1.5" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" @@ -11514,20 +11529,6 @@ abstract-leveldown@~0.12.1: dependencies: xtend "~3.0.0" -abstract-leveldown@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - integrity sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA== - dependencies: - xtend "~4.0.0" - -abstract-leveldown@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - integrity sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w== - dependencies: - xtend "~4.0.0" - accepts@^1.3.5, accepts@^1.3.7, accepts@~1.3.5, accepts@~1.3.7, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -12838,7 +12839,7 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async-eventemitter@0.2.4, async-eventemitter@^0.2.2: +async-eventemitter@0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== @@ -12896,12 +12897,7 @@ async-mutex@^0.5.0: dependencies: tslib "^2.4.0" -async@^1.4.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - -async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.6.0, async@^2.6.3, async@^2.6.4: +async@^2.4.0, async@^2.6.0, async@^2.6.3, async@^2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== @@ -13382,7 +13378,7 @@ bn.js@5.2.1, bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -14010,13 +14006,6 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -checkpoint-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - integrity sha1-BOTLUWuRQziTWB5tRgGnjpVS6gY= - dependencies: - functional-red-black-tree "^1.0.1" - cheerio-select@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" @@ -15493,13 +15482,6 @@ deferred-leveldown@~0.2.0: dependencies: abstract-leveldown "~0.12.1" -deferred-leveldown@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - integrity sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA== - dependencies: - abstract-leveldown "~2.6.0" - define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" @@ -16969,6 +16951,15 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eth-block-tracker@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-5.0.1.tgz#c5ad39902bd0454223b601ec0874f9fcc9f30eed" + integrity sha512-NVs+JDSux0FdmOrl3A2YDcQFkkYf9/qW9irvPmtC7bhMoPAe6oBlaqqe/m9Ixh5rkKqAox4mEyWGpsFmf/IsNw== + dependencies: + "@metamask/safe-event-emitter" "^2.0.0" + json-rpc-random-id "^1.0.1" + pify "^3.0.0" + eth-block-tracker@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz#dfc16085c6817cc30caabba381deb8d204c1c766" @@ -17007,13 +16998,6 @@ eth-ens-namehash@^1.0.2: idna-uts46 "^1.0.1" js-sha3 "^0.5.7" -eth-json-rpc-errors@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz#148377ef55155585981c21ff574a8937f9d6991f" - integrity sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg== - dependencies: - fast-safe-stringify "^2.0.6" - eth-json-rpc-filters@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz#0b3e370f017f5c6f58d3e7bd0756d8099ed85c56" @@ -17025,25 +17009,22 @@ eth-json-rpc-filters@^6.0.1: json-rpc-engine "^6.1.0" pify "^5.0.0" -eth-json-rpc-middleware@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.3.0.tgz#d3e72efb60b6f601f022ce01384481eaed552b6b" - integrity sha512-Acr+FaIHB0oIV0nWrCvepQghgA3FzYFvnMDXdTUeHQvAX/G6ioMbw1exGJs+6HirRjJ+MmkZqaArphx+PTrRNQ== +eth-json-rpc-middleware@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-9.0.1.tgz#193cb05174739fb736737bbbf992e13010c4b44e" + integrity sha512-5yLNjkedXA4LTIBzzU2f7aHFJqANPsc5qCdOZy6T2p7mlDLW+0q0YBQg6Lx4sHdamOWUnJwvm70qzPAqst5zSg== 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-json-rpc-errors "^1.0.1" - eth-query "^2.1.2" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.6.0" - ethereumjs-tx "^1.3.7" - ethereumjs-util "^5.1.2" - ethereumjs-vm "^2.6.0" - fetch-ponyfill "^4.0.0" - json-rpc-engine "^5.1.3" + 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" - safe-event-emitter "^1.0.1" eth-method-registry@^4.0.0: version "4.0.0" @@ -17068,28 +17049,13 @@ eth-query@^2.1.2: json-rpc-random-id "^1.0.0" xtend "^4.0.1" -eth-rpc-errors@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz#d7b22653c70dbf9defd4ef490fd08fe70608ca10" - integrity sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg== - dependencies: - fast-safe-stringify "^2.0.6" - -eth-rpc-errors@^4.0.2: +eth-rpc-errors@^4.0.2, eth-rpc-errors@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg== dependencies: fast-safe-stringify "^2.0.6" -eth-sig-util@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - integrity sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA= - dependencies: - ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util "^5.1.1" - eth-url-parser@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/eth-url-parser/-/eth-url-parser-1.0.4.tgz#310a99f331abdb8d603c74131568fb773e609cd8" @@ -17098,16 +17064,6 @@ eth-url-parser@1.0.4: bignumber.js "^7.2.1" qs "^6.5.2" -ethereum-common@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - integrity sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA== - -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - integrity sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ== - ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" @@ -17152,65 +17108,6 @@ ethereumjs-abi@0.6.6: bn.js "^4.10.0" ethereumjs-util "^5.0.0" -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version "0.6.8" - resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-account@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - integrity sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA== - dependencies: - ethereumjs-util "^5.0.0" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-block@^1.6.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - integrity sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg== - dependencies: - async "^2.0.1" - ethereum-common "0.2.0" - ethereumjs-tx "^1.2.2" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-block@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== - dependencies: - async "^2.0.1" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-common@^1.1.0, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" - integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== - -ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" - -ethereumjs-tx@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - ethereumjs-util@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz#e9c51e5549e8ebd757a339cc00f5380507e799c8" @@ -17224,7 +17121,7 @@ ethereumjs-util@6.1.0: safe-buffer "^5.1.1" secp256k1 "^3.0.1" -ethereumjs-util@^5.0.0, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2: +ethereumjs-util@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== @@ -17237,19 +17134,6 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2: rlp "^2.0.0" safe-buffer "^5.1.1" -ethereumjs-util@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.8, ethereumjs-util@^7.1.2: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" @@ -17261,23 +17145,6 @@ ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.8, ethereumjs-util@^7.1.2: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethereumjs-vm@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" - integrity sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - ethereumjs-account "^2.0.3" - ethereumjs-block "~2.2.0" - ethereumjs-common "^1.1.0" - ethereumjs-util "^6.0.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - ethereumjs-wallet@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz#2c000504b4c71e8f3782dabe1113d192522e99b6" @@ -17414,7 +17281,7 @@ ethjs-util@0.1.3: is-hex-prefixed "1.0.0" strip-hex-prefix "1.0.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3: +ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -17719,13 +17586,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fake-merkle-patricia-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - integrity sha1-S4w6z7Ugr635hgsfFM2M40As3dM= - dependencies: - checkpoint-store "^1.1.0" - fancy-log@^1.3.2: version "1.3.3" resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" @@ -17904,13 +17764,6 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -fetch-ponyfill@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" - integrity sha1-rjzl9zLGReq4fkroeTQUcJsjmJM= - dependencies: - node-fetch "~1.7.1" - figures@^3.0.0, figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -18452,11 +18305,6 @@ function.prototype.name@^1.1.0, function.prototype.name@^1.1.2, function.prototy es-abstract "^1.22.1" functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -19548,11 +19396,6 @@ image-to-base64@^2.2.0: dependencies: node-fetch "^2.6.0" -immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" - integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== - immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -21079,14 +20922,6 @@ json-pointer@^0.6.2: dependencies: foreach "^2.0.4" -json-rpc-engine@^5.1.3: - version "5.4.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz#75758609d849e1dba1e09021ae473f3ab63161e5" - integrity sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g== - dependencies: - eth-rpc-errors "^3.0.0" - safe-event-emitter "^1.0.1" - json-rpc-engine@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" @@ -21435,11 +21270,6 @@ level-blobs@^0.1.7: once "^1.3.0" readable-stream "^1.0.26-4" -level-codec@~7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== - level-concat-iterator@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" @@ -21447,20 +21277,6 @@ level-concat-iterator@^3.0.0: dependencies: catering "^2.1.0" -level-errors@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - integrity sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w== - dependencies: - errno "~0.1.1" - -level-errors@~1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - integrity sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig== - dependencies: - errno "~0.1.1" - level-filesystem@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/level-filesystem/-/level-filesystem-1.2.0.tgz#a00aca9919c4a4dfafdca6a8108d225aadff63b3" @@ -21495,16 +21311,6 @@ level-fix-range@~1.0.2: dependencies: string-range "~1.2" -level-iterator-stream@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - integrity sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0= - dependencies: - inherits "^2.0.1" - level-errors "^1.0.3" - readable-stream "^1.0.33" - xtend "^4.0.0" - level-peek@1.0.6, level-peek@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/level-peek/-/level-peek-1.0.6.tgz#bec51c72a82ee464d336434c7c876c3fcbcce77f" @@ -21540,14 +21346,6 @@ level-transcoder@^1.0.1: buffer "^6.0.3" module-error "^1.0.1" -level-ws@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - integrity sha1-Ny5RIXeSSgBCSwtDrvK7QkltIos= - dependencies: - readable-stream "~1.0.15" - xtend "~2.1.1" - leveldown@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.0.tgz#7ab1297706f70c657d1a72b31b40323aa612b9ee" @@ -21570,19 +21368,6 @@ levelup@^0.18.2: semver "~2.3.1" xtend "~3.0.0" -levelup@^1.2.1: - version "1.3.9" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - integrity sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ== - dependencies: - deferred-leveldown "~1.2.1" - level-codec "~7.0.0" - level-errors "~1.0.3" - level-iterator-stream "~1.3.0" - prr "~1.0.1" - semver "~5.4.1" - xtend "~4.0.0" - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -22034,7 +21819,7 @@ lru-cache@^7.14.0, lru-cache@^7.14.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -ltgt@^2.1.3, ltgt@~2.2.0: +ltgt@^2.1.3: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== @@ -22183,18 +21968,6 @@ mem@^4.0.0: mimic-fn "^2.0.0" p-is-promise "^2.0.0" -memdown@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - integrity sha1-tOThkhdGZP+65BNhqlAPMRnv4hU= - dependencies: - abstract-leveldown "~2.7.1" - functional-red-black-tree "^1.0.1" - immediate "^3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - memfs@^3.4.1, memfs@^3.4.12: version "3.6.0" resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" @@ -22236,20 +22009,6 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - integrity sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g== - dependencies: - async "^1.4.2" - ethereumjs-util "^5.0.0" - level-ws "0.0.0" - levelup "^1.2.1" - memdown "^1.0.0" - readable-stream "^2.0.0" - rlp "^2.0.0" - semaphore ">=1.0.1" - mersenne-twister@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a" @@ -23179,7 +22938,7 @@ node-fetch-native@^1.4.0, node-fetch-native@^1.4.1: resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.1.tgz#f95c74917d3cebc794cdae0cd2a9c7594aad0cb4" integrity sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw== -node-fetch@2.6.7, node-fetch@^2.0.0, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7, node-fetch@^2.7.0, node-fetch@~1.7.1: +node-fetch@2.6.7, node-fetch@^2.0.0, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7, node-fetch@^2.7.0: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -23522,11 +23281,6 @@ object-keys@~0.2.0: indexof "~0.0.1" is "~0.2.6" -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= - object.assign@^4.1.0, object.assign@^4.1.2, object.assign@^4.1.4, object.assign@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" @@ -26156,7 +25910,7 @@ readable-stream@2.3.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^1.0.26-4, readable-stream@^1.0.31, readable-stream@^1.0.33: +readable-stream@^1.0.26-4, readable-stream@^1.0.31: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= @@ -26190,7 +25944,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable process "^0.11.10" string_decoder "^1.3.0" -readable-stream@~1.0.15, readable-stream@~1.0.26, readable-stream@~1.0.26-4, readable-stream@~1.0.31: +readable-stream@~1.0.26, readable-stream@~1.0.26-4, readable-stream@~1.0.31: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= @@ -26738,7 +26492,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.2: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4, rlp@^2.2.6: +rlp@^2.0.0, rlp@^2.2.4, rlp@^2.2.6: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== @@ -26803,11 +26557,6 @@ run-parallel@^1.1.2, run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rustbn.js@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== - "rxjs@>= 6", rxjs@^7.5.5, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" @@ -26852,13 +26601,6 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-event-emitter@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - integrity sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg== - dependencies: - events "^3.0.0" - safe-json-stringify@~1: version "1.2.0" resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" @@ -26984,11 +26726,6 @@ selenium-webdriver@^3.6.0: tmp "0.0.30" xml2js "^0.4.17" -semaphore@>=1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -27028,11 +26765,6 @@ semver@~5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" integrity sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw== -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== - send@0.18.0, send@0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" @@ -28613,6 +28345,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tweetnacl-util@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" + integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== + tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -30023,13 +29760,6 @@ xtend@~2.0.4: is-object "~0.1.2" object-keys "~0.2.0" -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= - dependencies: - object-keys "~0.4.0" - xtend@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a" From e5648e104d2aec75f5fceaccbdf2e0ae43493ea3 Mon Sep 17 00:00:00 2001 From: Daniel <80175477+dan437@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:31:07 +0100 Subject: [PATCH 06/90] chore: Add a new transaction event (#10950) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Add a minimal version of the "Transaction Finalized" event, triggered [at the same time as in the extension](https://github.com/MetaMask/metamask-extension/blob/2b45577566518deff4cbacd557660b7eef0657b5/app/scripts/lib/transaction/metrics.ts#L241-L249). This PR also fixes metrics passed from the STX controller. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TXL-249 ## **Manual testing steps** 1. Submit a Send transaction on a Sepolia testnet 2. You will see the `Transaction Finalized` event in console if you are running the mobile app locally and it will have an additional payload if it's a smart transaction ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: Derek Brans --- app/core/Analytics/MetaMetrics.events.ts | 7 + app/core/{Engine.test.js => Engine.test.ts} | 213 +++++++++++++++++--- app/core/Engine.ts | 148 +++++++++++--- app/util/smart-transactions/index.test.ts | 130 ++++++++++++ app/util/smart-transactions/index.ts | 52 +++-- package.json | 2 +- yarn.lock | 8 +- 7 files changed, 490 insertions(+), 70 deletions(-) rename app/core/{Engine.test.js => Engine.test.ts} (51%) diff --git a/app/core/Analytics/MetaMetrics.events.ts b/app/core/Analytics/MetaMetrics.events.ts index 012fb1c97e5..2b18644ebc8 100644 --- a/app/core/Analytics/MetaMetrics.events.ts +++ b/app/core/Analytics/MetaMetrics.events.ts @@ -359,8 +359,13 @@ enum EVENT_NAME { // Smart transactions SMART_TRANSACTION_OPT_IN = 'Smart Transaction Opt In', + // Transactions + // Fired when the transaction reaches a final state (e.g., CONFIRMED, FAILED, DROPPED). + TRANSACTION_FINALIZED = 'Transaction Finalized', + // Simulations INCOMPLETE_ASSET_DISPLAYED = 'Incomplete Asset Displayed', + // Nft auto detection modal NFT_AUTO_DETECTION_ENABLED_MODAL = 'Nft Autodetection Enabled from modal', NFT_AUTO_DETECTION_DISBLED_MODAL = 'Nft Autodetection Disabled from modal', @@ -842,6 +847,8 @@ const events = { INCOMPLETE_ASSET_DISPLAYED: generateOpt( EVENT_NAME.INCOMPLETE_ASSET_DISPLAYED, ), + // Transactions + TRANSACTION_FINALIZED: generateOpt(EVENT_NAME.TRANSACTION_FINALIZED), // Nft auto detection modal NFT_AUTO_DETECTION_MODAL_ENABLE: generateOpt( EVENT_NAME.NFT_AUTO_DETECTION_ENABLED_MODAL, diff --git a/app/core/Engine.test.js b/app/core/Engine.test.ts similarity index 51% rename from app/core/Engine.test.js rename to app/core/Engine.test.ts index b21f4c5ce91..835365d6fbb 100644 --- a/app/core/Engine.test.js +++ b/app/core/Engine.test.ts @@ -1,11 +1,29 @@ -import Engine from './Engine'; +import Engine, { + Engine as EngineClass, + EngineState, + TransactionEventPayload, +} from './Engine'; import { backgroundState } from '../util/test/initial-root-state'; import { zeroAddress } from 'ethereumjs-util'; import { createMockAccountsControllerState } from '../util/test/accountsControllerTestUtils'; import { mockNetworkState } from '../util/test/network'; +import MetaMetrics from './Analytics/MetaMetrics'; +import { store } from '../store'; +import { MetaMetricsEvents } from './Analytics'; +import { NetworkState, RpcEndpointType } from '@metamask/network-controller'; +import { Hex } from '@metamask/utils'; +import { MarketDataDetails } from '../components/UI/Tokens'; +import { TransactionMeta } from '@metamask/transaction-controller'; +import { RootState } from '../reducers'; +import { MetricsEventBuilder } from './Analytics/MetricsEventBuilder'; jest.unmock('./Engine'); -jest.mock('../store', () => ({ store: { getState: jest.fn(() => ({})) } })); +jest.mock('../store', () => ({ + store: { getState: jest.fn(() => ({ engine: {} })) }, +})); +jest.mock('../selectors/smartTransactionsController', () => ({ + selectShouldUseSmartTransaction: jest.fn().mockReturnValue(false), +})); describe('Engine', () => { it('should expose an API', () => { @@ -66,19 +84,30 @@ describe('Engine', () => { }); describe('getTotalFiatAccountBalance', () => { - let engine; + let engine: EngineClass; afterEach(() => engine?.destroyEngineInstance()); const selectedAddress = '0x9DeE4BF1dE9E3b930E511Db5cEBEbC8d6F855Db0'; - const chainId = '0x1'; + const chainId: Hex = '0x1'; const ticker = 'ETH'; const ethConversionRate = 4000; // $4,000 / ETH + const ethBalance = 1; - const state = { + const state: Partial = { AccountsController: createMockAccountsControllerState( [selectedAddress], selectedAddress, ), + AccountTrackerController: { + accountsByChainId: { + [chainId]: { + [selectedAddress]: { balance: (ethBalance * 1e18).toString() }, + }, + }, + accounts: { + [selectedAddress]: { balance: (ethBalance * 1e18).toString() }, + }, + }, NetworkController: { state: { ...mockNetworkState({ @@ -86,14 +115,21 @@ describe('Engine', () => { id: '0x1', nickname: 'mainnet', ticker: 'ETH', - type: 'infura', + type: RpcEndpointType.Infura, }), }, - }, + // TODO(dbrans): Investigate why the shape of the NetworkController state in this + // test is {state: NetworkState} instead of just NetworkState. + } as unknown as NetworkState, CurrencyRateController: { currencyRates: { - [ticker]: { conversionRate: ethConversionRate }, + [ticker]: { + conversionRate: ethConversionRate, + conversionDate: 0, + usdConversionRate: ethConversionRate, + }, }, + currentCurrency: ticker, }, }; @@ -109,24 +145,16 @@ describe('Engine', () => { }); it('calculates when theres only ETH', () => { - const ethBalance = 1; // 1 ETH const ethPricePercentChange1d = 5; // up 5% engine = Engine.init({ ...state, - AccountTrackerController: { - accountsByChainId: { - [chainId]: { - [selectedAddress]: { balance: ethBalance * 1e18 }, - }, - }, - }, TokenRatesController: { marketData: { [chainId]: { [zeroAddress()]: { pricePercentChange1d: ethPricePercentChange1d, - }, + } as MarketDataDetails, }, }, }, @@ -144,7 +172,6 @@ describe('Engine', () => { }); it('calculates when there are ETH and tokens', () => { - const ethBalance = 1; const ethPricePercentChange1d = 5; const tokens = [ @@ -164,18 +191,18 @@ describe('Engine', () => { engine = Engine.init({ ...state, - AccountTrackerController: { - accountsByChainId: { - [chainId]: { - [selectedAddress]: { balance: ethBalance * 1e18 }, - }, - }, - }, TokensController: { tokens: tokens.map((token) => ({ address: token.address, balance: token.balance, + decimals: 18, + symbol: 'TEST', })), + ignoredTokens: [], + detectedTokens: [], + allTokens: {}, + allIgnoredTokens: {}, + allDetectedTokens: {}, }, TokenRatesController: { marketData: { @@ -203,7 +230,7 @@ describe('Engine', () => { const ethFiat = ethBalance * ethConversionRate; const [tokenFiat, tokenFiat1dAgo] = tokens.reduce( ([fiat, fiat1d], token) => { - const value = token.balance * token.price * ethConversionRate; + const value = Number(token.price) * token.balance * ethConversionRate; return [ fiat + value, fiat1d + value / (1 + token.pricePercentChange1d / 100), @@ -221,3 +248,137 @@ describe('Engine', () => { }); }); }); + +describe('Transaction event handlers', () => { + let engine: EngineClass; + + beforeEach(() => { + engine = Engine.init({}); + jest.spyOn(MetaMetrics.getInstance(), 'trackEvent').mockImplementation(); + jest.spyOn(store, 'getState').mockReturnValue({} as RootState); + }); + + afterEach(() => { + engine?.destroyEngineInstance(); + jest.clearAllMocks(); + }); + + describe('_handleTransactionFinalizedEvent', () => { + it('tracks event with basic properties when smart transactions are disabled', async () => { + const properties = { status: 'confirmed' }; + const transactionEventPayload: TransactionEventPayload = { + transactionMeta: { hash: '0x123' } as TransactionMeta, + }; + + await engine._handleTransactionFinalizedEvent( + transactionEventPayload, + properties, + ); + + const expectedEvent = MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties(properties) + .build(); + + expect(MetaMetrics.getInstance().trackEvent).toHaveBeenCalledWith( + expectedEvent, + ); + }); + + it('does not process smart transaction metrics if transactionMeta is missing', async () => { + const properties = { status: 'failed' }; + const transactionEventPayload = {} as TransactionEventPayload; + + await engine._handleTransactionFinalizedEvent( + transactionEventPayload, + properties, + ); + + const expectedEvent = MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties(properties) + .build(); + + expect(MetaMetrics.getInstance().trackEvent).toHaveBeenCalledWith( + expectedEvent, + ); + }); + }); + + describe('Transaction status handlers', () => { + it('tracks dropped transactions', async () => { + const transactionEventPayload: TransactionEventPayload = { + transactionMeta: { hash: '0x123' } as TransactionMeta, + }; + + await engine._handleTransactionDropped(transactionEventPayload); + + const expectedEvent = MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties({ status: 'dropped' }) + .build(); + + expect(MetaMetrics.getInstance().trackEvent).toHaveBeenCalledWith( + expectedEvent, + ); + }); + + it('tracks confirmed transactions', async () => { + const transactionMeta = { hash: '0x123' } as TransactionMeta; + + await engine._handleTransactionConfirmed(transactionMeta); + + const expectedEvent = MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties({ status: 'confirmed' }) + .build(); + + expect(MetaMetrics.getInstance().trackEvent).toHaveBeenCalledWith( + expectedEvent, + ); + }); + + it('tracks failed transactions', async () => { + const transactionEventPayload: TransactionEventPayload = { + transactionMeta: { hash: '0x123' } as TransactionMeta, + }; + + await engine._handleTransactionFailed(transactionEventPayload); + + const expectedEvent = MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties({ status: 'failed' }) + .build(); + + expect(MetaMetrics.getInstance().trackEvent).toHaveBeenCalledWith( + expectedEvent, + ); + }); + }); + + describe('_addTransactionControllerListeners', () => { + it('subscribes to transaction events', () => { + jest.spyOn(engine.controllerMessenger, 'subscribe'); + + engine._addTransactionControllerListeners(); + + expect(engine.controllerMessenger.subscribe).toHaveBeenCalledWith( + 'TransactionController:transactionDropped', + engine._handleTransactionDropped, + ); + expect(engine.controllerMessenger.subscribe).toHaveBeenCalledWith( + 'TransactionController:transactionConfirmed', + engine._handleTransactionConfirmed, + ); + expect(engine.controllerMessenger.subscribe).toHaveBeenCalledWith( + 'TransactionController:transactionFailed', + engine._handleTransactionFailed, + ); + }); + }); +}); diff --git a/app/core/Engine.ts b/app/core/Engine.ts index 684f12c6164..07a4d19fbb4 100644 --- a/app/core/Engine.ts +++ b/app/core/Engine.ts @@ -74,6 +74,7 @@ import { TransactionController, TransactionControllerEvents, TransactionControllerState, + TransactionMeta, TransactionControllerOptions, } from '@metamask/transaction-controller'; import { @@ -241,8 +242,8 @@ import { MetaMetricsEventName, } from '@metamask/smart-transactions-controller/dist/constants'; import { - getSmartTransactionMetricsProperties, - getSmartTransactionMetricsSensitiveProperties, + getSmartTransactionMetricsProperties as getSmartTransactionMetricsPropertiesType, + getSmartTransactionMetricsSensitiveProperties as getSmartTransactionMetricsSensitivePropertiesType, } from '@metamask/smart-transactions-controller/dist/utils'; ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) import { snapKeyringBuilder } from './SnapKeyring'; @@ -251,7 +252,10 @@ import { keyringSnapPermissionsBuilder } from './SnapKeyring/keyringSnapsPermiss import { HandleSnapRequestArgs } from './Snaps/types'; import { handleSnapRequest } from './Snaps/utils'; ///: END:ONLY_INCLUDE_IF +import { getSmartTransactionMetricsProperties } from '../util/smart-transactions'; import { trace } from '../util/trace'; +import { MetricsEventBuilder } from './Analytics/MetricsEventBuilder'; +import { JsonMap } from './Analytics/MetaMetrics.types'; const NON_EMPTY = 'NON_EMPTY'; @@ -435,11 +439,17 @@ export type ControllerMessenger = ExtendedControllerMessenger< GlobalEvents >; +export interface TransactionEventPayload { + transactionMeta: TransactionMeta; + actionId?: string; + error?: string; +} + /** * Core controller responsible for composing other metamask controllers together * and exposing convenience methods for common wallet operations. */ -class Engine { +export class Engine { /** * The global Engine singleton */ @@ -1327,7 +1337,7 @@ class Engine { return Boolean( hasProperty(showIncomingTransactions, currentChainId) && - showIncomingTransactions?.[currentHexChainId], + showIncomingTransactions?.[currentHexChainId], ); }, updateTransactions: true, @@ -1366,9 +1376,11 @@ class Engine { params: { event: MetaMetricsEventName; category: MetaMetricsEventCategory; - properties?: ReturnType; + properties?: ReturnType< + typeof getSmartTransactionMetricsPropertiesType + >; sensitiveProperties?: ReturnType< - typeof getSmartTransactionMetricsSensitiveProperties + typeof getSmartTransactionMetricsSensitivePropertiesType >; }, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -1376,16 +1388,13 @@ class Engine { metaMetricsId?: string; }, ) => { - const { event, category, ...restParams } = params; - MetaMetrics.getInstance().trackEvent( - { - category, - properties: { - name: event, - }, - }, - restParams, + MetricsEventBuilder.createEventBuilder({ + category: params.event, + }) + .addProperties(params.properties || {}) + .addSensitiveProperties(params.sensitiveProperties || {}) + .build(), ); }; this.smartTransactionsController = new SmartTransactionsController({ @@ -1678,7 +1687,7 @@ class Engine { (state: NetworkState) => { if ( state.networksMetadata[state.selectedNetworkClientId].status === - NetworkStatus.Available && + NetworkStatus.Available && networkController.getNetworkClientById( networkController?.state.selectedNetworkClientId, ).configuration.chainId !== currentChainId @@ -1703,9 +1712,10 @@ class Engine { } catch (error) { console.error( error, - `Network ID not changed, current chainId: ${networkController.getNetworkClientById( - networkController?.state.selectedNetworkClientId, - ).configuration.chainId + `Network ID not changed, current chainId: ${ + networkController.getNetworkClientById( + networkController?.state.selectedNetworkClientId, + ).configuration.chainId }`, ); } @@ -1722,10 +1732,97 @@ class Engine { this.configureControllersOnNetworkChange(); this.startPolling(); this.handleVaultBackup(); + this._addTransactionControllerListeners(); Engine.instance = this; } + // Logs the "Transaction Finalized" event after a transaction was either confirmed, dropped or failed. + _handleTransactionFinalizedEvent = async ( + transactionEventPayload: TransactionEventPayload, + properties: JsonMap, + ) => { + const shouldUseSmartTransaction = selectShouldUseSmartTransaction( + store.getState(), + ); + if ( + !shouldUseSmartTransaction || + !transactionEventPayload.transactionMeta + ) { + MetaMetrics.getInstance().trackEvent( + MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties(properties) + .build(), + ); + return; + } + const { transactionMeta } = transactionEventPayload; + const { SmartTransactionsController } = this.context; + const waitForSmartTransaction = true; + const smartTransactionMetricsProperties = + await getSmartTransactionMetricsProperties( + SmartTransactionsController, + transactionMeta, + waitForSmartTransaction, + this.controllerMessenger, + ); + MetaMetrics.getInstance().trackEvent( + MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.TRANSACTION_FINALIZED, + ) + .addProperties(smartTransactionMetricsProperties) + .addProperties(properties) + .build(), + ); + }; + + _handleTransactionDropped = async ( + transactionEventPayload: TransactionEventPayload, + ) => { + const properties = { status: 'dropped' }; + await this._handleTransactionFinalizedEvent( + transactionEventPayload, + properties, + ); + }; + + _handleTransactionConfirmed = async (transactionMeta: TransactionMeta) => { + const properties = { status: 'confirmed' }; + await this._handleTransactionFinalizedEvent( + { transactionMeta }, + properties, + ); + }; + + _handleTransactionFailed = async ( + transactionEventPayload: TransactionEventPayload, + ) => { + const properties = { status: 'failed' }; + await this._handleTransactionFinalizedEvent( + transactionEventPayload, + properties, + ); + }; + + _addTransactionControllerListeners() { + this.controllerMessenger.subscribe( + 'TransactionController:transactionDropped', + this._handleTransactionDropped, + ); + + this.controllerMessenger.subscribe( + 'TransactionController:transactionConfirmed', + this._handleTransactionConfirmed, + ); + + this.controllerMessenger.subscribe( + 'TransactionController:transactionFailed', + this._handleTransactionFailed, + ); + } + handleVaultBackup() { this.controllerMessenger.subscribe( AppConstants.KEYRING_STATE_CHANGE_EVENT, @@ -1834,7 +1931,7 @@ class Engine { const decimalsToShow = (currentCurrency === 'usd' && 2) || undefined; if ( accountsByChainId?.[toHexadecimal(chainId)]?.[ - selectSelectedInternalAccountChecksummedAddress + selectSelectedInternalAccountChecksummedAddress ] ) { ethFiat = weiToFiatNumber( @@ -1866,9 +1963,9 @@ class Engine { item.balance || (item.address in tokenBalances ? renderFromTokenMinimalUnit( - tokenBalances[item.address], - item.decimals, - ) + tokenBalances[item.address], + item.decimals, + ) : undefined); const tokenBalanceFiat = balanceToFiatNumber( // TODO: Fix this by handling or eliminating the undefined case @@ -1922,7 +2019,6 @@ class Engine { return snapKeyring; }; - /** * Removes an account from state / storage. * @@ -2256,7 +2352,7 @@ export default { instance = null; }, - init(state: Record | undefined, keyringState = null) { + init(state: Partial | undefined, keyringState = null) { instance = Engine.instance || new Engine(state, keyringState); Object.freeze(instance); return instance; @@ -2299,6 +2395,6 @@ export default { removeAccount: async (address: string) => { assertEngineExists(instance); return await instance.removeAccount(address); - } + }, ///: END:ONLY_INCLUDE_IF }; diff --git a/app/util/smart-transactions/index.test.ts b/app/util/smart-transactions/index.test.ts index cff25d254a0..aeec09642c6 100644 --- a/app/util/smart-transactions/index.test.ts +++ b/app/util/smart-transactions/index.test.ts @@ -3,7 +3,10 @@ import { getShouldStartApprovalRequest, getShouldUpdateApprovalRequest, getTransactionType, + getSmartTransactionMetricsProperties } from './index'; +import SmartTransactionsController from '@metamask/smart-transactions-controller'; +import type { ControllerMessenger } from '../../core/Engine'; describe('Smart Transactions utils', () => { describe('getTransactionType', () => { @@ -307,4 +310,131 @@ describe('Smart Transactions utils', () => { expect(res).toBe(false); }); }); + describe('getSmartTransactionMetricsProperties', () => { + let smartTransactionsController: SmartTransactionsController; + let controllerMessenger: ControllerMessenger; + + beforeEach(() => { + smartTransactionsController = { + getSmartTransactionByMinedTxHash: jest.fn(), + } as unknown as SmartTransactionsController; + controllerMessenger = { + subscribe: jest.fn(), + } as unknown as ControllerMessenger; + }); + + it('returns empty object if transactionMeta is undefined', async () => { + const result = await getSmartTransactionMetricsProperties( + smartTransactionsController, + undefined, + false, + controllerMessenger + ); + expect(result).toEqual({}); + }); + + it('returns metrics if smartTransaction is found by getSmartTransactionByMinedTxHash', async () => { + const transactionMeta = { hash: '0x123' } as TransactionMeta; + const smartTransaction = { + statusMetadata: { + duplicated: true, + timedOut: false, + proxied: true, + }, + }; + (smartTransactionsController.getSmartTransactionByMinedTxHash as jest.Mock).mockReturnValue(smartTransaction); + + const result = await getSmartTransactionMetricsProperties( + smartTransactionsController, + transactionMeta, + false, + controllerMessenger + ); + expect(result).toEqual({ + smart_transaction_duplicated: true, + smart_transaction_timed_out: false, + smart_transaction_proxied: true, + }); + }); + + it('waits for smartTransaction if not found and waitForSmartTransaction is true', async () => { + const transactionMeta = { hash: '0x123' } as TransactionMeta; + const smartTransaction = { + statusMetadata: { + duplicated: false, + timedOut: true, + proxied: false, + }, + }; + (smartTransactionsController.getSmartTransactionByMinedTxHash as jest.Mock).mockReturnValue(undefined); + (controllerMessenger.subscribe as jest.Mock).mockImplementation((event, callback) => { + if (event === 'SmartTransactionsController:smartTransactionConfirmationDone') { + setTimeout(() => callback(smartTransaction), 100); + } + }); + + const result = await getSmartTransactionMetricsProperties( + smartTransactionsController, + transactionMeta, + true, + controllerMessenger + ); + expect(result).toEqual({ + smart_transaction_duplicated: false, + smart_transaction_timed_out: true, + smart_transaction_proxied: false, + }); + }); + + it('returns empty object if smartTransaction is not found and waitForSmartTransaction is false', async () => { + const transactionMeta = { hash: '0x123' } as TransactionMeta; + (smartTransactionsController.getSmartTransactionByMinedTxHash as jest.Mock).mockReturnValue(undefined); + + const result = await getSmartTransactionMetricsProperties( + smartTransactionsController, + transactionMeta, + false, + controllerMessenger + ); + expect(result).toEqual({}); + }); + + it('returns empty object if smartTransaction is found but statusMetadata is undefined', async () => { + const transactionMeta = { hash: '0x123' } as TransactionMeta; + const smartTransaction = {}; + (smartTransactionsController.getSmartTransactionByMinedTxHash as jest.Mock).mockReturnValue(smartTransaction); + + const result = await getSmartTransactionMetricsProperties( + smartTransactionsController, + transactionMeta, + false, + controllerMessenger + ); + expect(result).toEqual({}); + }); + + it('returns metrics if smartTransaction is found with statusMetadata', async () => { + const transactionMeta = { hash: '0x123' } as TransactionMeta; + const smartTransaction = { + statusMetadata: { + duplicated: true, + timedOut: false, + proxied: true, + }, + }; + (smartTransactionsController.getSmartTransactionByMinedTxHash as jest.Mock).mockReturnValue(smartTransaction); + + const result = await getSmartTransactionMetricsProperties( + smartTransactionsController, + transactionMeta, + false, + controllerMessenger + ); + expect(result).toEqual({ + smart_transaction_duplicated: true, + smart_transaction_timed_out: false, + smart_transaction_proxied: true, + }); + }); + }); }); diff --git a/app/util/smart-transactions/index.ts b/app/util/smart-transactions/index.ts index bee58491964..82ce0d8bd51 100644 --- a/app/util/smart-transactions/index.ts +++ b/app/util/smart-transactions/index.ts @@ -8,6 +8,10 @@ import { getIsNativeTokenTransferred, } from '../transactions'; import SmartTransactionsController from '@metamask/smart-transactions-controller'; +import { SmartTransaction } from '@metamask/smart-transactions-controller/dist/types'; +import type { ControllerMessenger } from '../../core/Engine'; + +const TIMEOUT_FOR_SMART_TRANSACTION_CONFIRMATION_DONE_EVENT = 10000; export const getTransactionType = ( transactionMeta: TransactionMeta, @@ -74,25 +78,47 @@ export const getShouldUpdateApprovalRequest = ( isSwapTransaction: boolean, ): boolean => isDapp || isSend || isSwapTransaction; -export const getSmartTransactionMetricsProperties = ( +const waitForSmartTransactionConfirmationDone = ( + controllerMessenger: ControllerMessenger, +): Promise => new Promise((resolve) => { + controllerMessenger.subscribe( + 'SmartTransactionsController:smartTransactionConfirmationDone', + async (smartTransaction: SmartTransaction) => { + resolve(smartTransaction); + }, + ); + setTimeout(() => { + resolve(undefined); // In a rare case we don't get the "smartTransactionConfirmationDone" event within 10 seconds, we resolve with undefined to continue. + }, TIMEOUT_FOR_SMART_TRANSACTION_CONFIRMATION_DONE_EVENT); +}); + +export const getSmartTransactionMetricsProperties = async ( smartTransactionsController: SmartTransactionsController, transactionMeta: TransactionMeta | undefined, + waitForSmartTransaction: boolean, + controllerMessenger?: ControllerMessenger ) => { if (!transactionMeta) return {}; - - const smartTransaction = + let smartTransaction = smartTransactionsController.getSmartTransactionByMinedTxHash( transactionMeta.hash, ); - - if (smartTransaction?.statusMetadata) { - const { duplicated, timedOut, proxied } = smartTransaction.statusMetadata; - return { - duplicated, - timedOut, - proxied, - }; + const shouldWaitForSmartTransactionConfirmationDoneEvent = + waitForSmartTransaction && + !smartTransaction?.statusMetadata && // We get this after polling for a status for a Smart Transaction. + controllerMessenger; + if (shouldWaitForSmartTransactionConfirmationDoneEvent) { + smartTransaction = await waitForSmartTransactionConfirmationDone( + controllerMessenger + ); } - - return {}; + if (!smartTransaction?.statusMetadata) { + return {}; + } + const { duplicated, timedOut, proxied } = smartTransaction.statusMetadata; + return { + smart_transaction_duplicated: duplicated, + smart_transaction_timed_out: timedOut, + smart_transaction_proxied: proxied, + }; }; diff --git a/package.json b/package.json index 64c97bd6ba6..49309856adf 100644 --- a/package.json +++ b/package.json @@ -181,7 +181,7 @@ "@metamask/selected-network-controller": "^15.0.2", "@metamask/signature-controller": "^20.1.0", "@metamask/slip44": "3.1.0", - "@metamask/smart-transactions-controller": "^13.0.0", + "@metamask/smart-transactions-controller": "^13.1.0", "@metamask/snaps-controllers": "^9.8.0", "@metamask/snaps-execution-environments": "^6.7.2", "@metamask/snaps-rpc-methods": "^9.1.4", diff --git a/yarn.lock b/yarn.lock index eb76c4231d2..0de7e3f473c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5383,10 +5383,10 @@ resolved "https://registry.yarnpkg.com/@metamask/slip44/-/slip44-4.0.0.tgz#690a52d2ba74ea677d9bd0e827a90c8809fbecd3" integrity sha512-MQMocMvFmp1MWownjKMuxevivwYeNQPSpNyIg9K7nmxKuoatp5NUc9L8EJ3Bh//rOfl6fBfXn9byfS0t+NE02Q== -"@metamask/smart-transactions-controller@^13.0.0": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@metamask/smart-transactions-controller/-/smart-transactions-controller-13.0.0.tgz#4a1f47cc5831598edc1bffb00ff74dbda6a3499e" - integrity sha512-7tNtCBXmkWnjHRHVskd2NuJnn+nAZQ3r0oX8QOcc4yINzTk+rBTPEMbPyCmlGP8md53t2EeTuM80iLO61BTGug== +"@metamask/smart-transactions-controller@^13.1.0": + version "13.1.0" + resolved "https://registry.yarnpkg.com/@metamask/smart-transactions-controller/-/smart-transactions-controller-13.1.0.tgz#0cb4acf14cbc0b1aeecd118f0728820c7a074888" + integrity sha512-kl3CRl+eKpegc/L8QIN5ZSR3e3eYIi1rKdAYJYTbOs3jHD8KW288XeuSP8S4puixWoJwwxrlTZ0f7LSUmmR9VQ== dependencies: "@babel/runtime" "^7.24.1" "@ethereumjs/tx" "^5.2.1" From 9f1068529bbf751af31edecee15c3e2f0dba408f Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Mon, 28 Oct 2024 14:19:10 +0100 Subject: [PATCH 07/90] fix: fix block explorer return button (#12036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** After trying to add a block explorer the Add Custom Network modal pops-up. I am adding block explorer by using device keypad enter button because the Add Block Explorer URL button is not reachable, keypad in the way. May be because of the keypad that is causing this. Have not been able to successfully add a block explorer. ## **Related issues** Fixes: #11992 ## **Manual testing steps** 1. Go to add network form 2. fill the form 3. when you fill the block explorer form click on return keyboard button ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../NetworksSettings/NetworkSettings/index.js | 7 ++++- e2e/pages/Settings/NetworksView.js | 31 +++++++++++++++++++ e2e/resources/networks.e2e.js | 3 +- .../Settings/NetworksView.selectors.js | 2 ++ e2e/specs/networks/add-custom-rpc.spec.js | 8 +++-- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js index 17e68d679a7..67815bae912 100644 --- a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js +++ b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js @@ -2065,6 +2065,7 @@ export class NetworkSettings extends PureComponent { { + this.onBlockExplorerItemAdd(blockExplorerUrlForm); + }} keyboardAppearance={themeAppearance} /> {blockExplorerUrl && @@ -2247,6 +2250,7 @@ export class NetworkSettings extends PureComponent { { this.onBlockExplorerItemAdd(blockExplorerUrlForm); @@ -2324,6 +2328,7 @@ export class NetworkSettings extends PureComponent { this.openAddBlockExplorerForm(); this.closeBlockExplorerModal(); }} + testID={NetworksViewSelectorsIDs.ADD_BLOCK_EXPLORER} width={ButtonWidthTypes.Auto} labelTextVariant={TextVariant.DisplayMD} /> diff --git a/e2e/pages/Settings/NetworksView.js b/e2e/pages/Settings/NetworksView.js index 5ab1cdde96d..5747627980e 100644 --- a/e2e/pages/Settings/NetworksView.js +++ b/e2e/pages/Settings/NetworksView.js @@ -27,6 +27,16 @@ class NetworkView { return Matchers.getElementByID(NetworksViewSelectorsIDs.ICON_BUTTON_RPC); } + get addBlockExplorerDropDownButton() { + return Matchers.getElementByID( + NetworksViewSelectorsIDs.ICON_BUTTON_BLOCK_EXPLORER, + ); + } + + get addBlockExplorerButton() { + return Matchers.getElementByID(NetworksViewSelectorsIDs.ADD_BLOCK_EXPLORER); + } + get addRpcButton() { return Matchers.getElementByID(NetworksViewSelectorsIDs.ADD_RPC_BUTTON); } @@ -91,6 +101,12 @@ class NetworkView { ); } + get networkBlockExplorerInput() { + return Matchers.getElementByID( + NetworksViewSelectorsIDs.BLOCK_EXPLORER_INPUT, + ); + } + get rpcAddButton() { return Matchers.getElementByID( NetworksViewSelectorsIDs.ADD_CUSTOM_NETWORK_BUTTON, @@ -138,6 +154,14 @@ class NetworkView { await Gestures.waitAndTap(this.addRpcDropDownButton); } + async tapBlockExplorerDownButton() { + await Gestures.waitAndTap(this.addBlockExplorerDropDownButton); + } + + async tapBlockExplorerButton() { + await Gestures.waitAndTap(this.addBlockExplorerButton); + } + async tapAddRpcButton() { await Gestures.waitAndTap(this.addRpcButton); } @@ -192,6 +216,13 @@ class NetworkView { ); } + async typeInNetworkBlockExplorer(networkBlockExplorer) { + await Gestures.typeTextAndHideKeyboard( + this.networkBlockExplorerInput, + networkBlockExplorer, + ); + } + async clearRpcInputBox() { await Gestures.clearField(this.rpcURLInput); } diff --git a/e2e/resources/networks.e2e.js b/e2e/resources/networks.e2e.js index a348bded2e6..fd6fc94a4a7 100644 --- a/e2e/resources/networks.e2e.js +++ b/e2e/resources/networks.e2e.js @@ -1,4 +1,4 @@ -import { toHex } from '@metamask/controller-utils'; +import { BlockExplorerUrl, toHex } from '@metamask/controller-utils'; /* eslint-disable @typescript-eslint/no-require-imports, import/no-commonjs */ const InfuraKey = process.env.MM_INFURA_PROJECT_ID; @@ -109,6 +109,7 @@ const CustomNetworks = { rpcUrl: 'https://rpc.gnosischain.com', nickname: 'Gnosis', ticker: 'xDAI', + BlockExplorerUrl: 'https://gnosisscan.io', }, }, }; diff --git a/e2e/selectors/Settings/NetworksView.selectors.js b/e2e/selectors/Settings/NetworksView.selectors.js index 85926b42264..0f8b32eb68d 100644 --- a/e2e/selectors/Settings/NetworksView.selectors.js +++ b/e2e/selectors/Settings/NetworksView.selectors.js @@ -6,6 +6,7 @@ export const NetworksViewSelectorsIDs = { ADD_NETWORKS_BUTTON: 'add-network-button', NETWORK_NAME_INPUT: 'input-network-name', BLOCK_EXPLORER_INPUT: 'block-explorer', + ADD_BLOCK_EXPLORER: 'add-block-explorer-button', RPC_URL_INPUT: 'input-rpc-url', CHAIN_INPUT: 'input-chain-id', NETWORKS_SYMBOL_INPUT: 'input-network-symbol', @@ -20,6 +21,7 @@ export const NetworksViewSelectorsIDs = { SEARCH_NETWORK_INPUT_BOX_ID: 'network-search-input', CONTAINER: 'network-form-container', ICON_BUTTON_RPC: 'drop-down-rpc-menu', + ICON_BUTTON_BLOCK_EXPLORER: 'drop-down-block-explorer-menu', ADD_RPC_BUTTON: 'add-rpc-button', RPC_NAME_INPUT: 'input-rpc-name', }; diff --git a/e2e/specs/networks/add-custom-rpc.spec.js b/e2e/specs/networks/add-custom-rpc.spec.js index a93af0334fd..7a6d7d4e4f7 100644 --- a/e2e/specs/networks/add-custom-rpc.spec.js +++ b/e2e/specs/networks/add-custom-rpc.spec.js @@ -17,8 +17,6 @@ import { getFixturesServerPort } from '../../fixtures/utils'; import FixtureServer from '../../fixtures/fixture-server'; import Assertions from '../../utils/Assertions'; import { CustomNetworks } from '../../resources/networks.e2e'; -import Gestures from '../../utils/Gestures'; -import Matchers from '../../utils/Matchers'; const fixtureServer = new FixtureServer(); @@ -75,6 +73,12 @@ describe(Regression('Custom RPC Tests'), () => { await NetworkView.tapChainIDLabel(); // Focus outside of text input field + await NetworkView.tapBlockExplorerDownButton(); + await NetworkView.tapBlockExplorerButton(); + await NetworkView.typeInNetworkBlockExplorer( + `${CustomNetworks.Gnosis.providerConfig.BlockExplorerUrl}\n`, + ); + if (device.getPlatform() === 'ios') { await NetworkView.tapChainIDLabel(); // Focus outside of text input field await NetworkView.tapChainIDLabel(); // Focus outside of text input field From 77494ba357ce77562bf1ca8c8ebab837f9939c09 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:01:30 +0000 Subject: [PATCH 08/90] feat: updated example envs and README (#12027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR implements Firebase SDK integration on iOS, addressing a need for creating GoogleServices-info.plist file at build process thus avoiding leaving project details exposed. Although this isn't an issue as stated [here](https://firebase.google.com/docs/projects/api-keys) and [here](https://stackoverflow.com/questions/37482366/is-it-safe-to-expose-firebase-apikey-to-the-public), we're just trying to minimize risk even when they're very low already. ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ![377832039-a083aab0-6641-4e78-a79b-567e5c78fe71](https://github.com/user-attachments/assets/7be4ae5a-b359-48b6-82b7-1d3963ff7975) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .android.env.example | 2 +- .gitignore | 1 + .ios.env.example | 2 +- .js.env.example | 3 +- README.md | 16 ++++++---- .../GoogleService-Info-example.plist | 30 +++++++++++++++++++ ios/GoogleServices/GoogleService-Info.plist | 26 ++++++++++++++++ ios/MetaMask.xcodeproj/project.pbxproj | 8 +++++ .../xcschemes/MetaMask-QA.xcscheme | 20 ++++++++++++- .../xcshareddata/xcschemes/MetaMask.xcscheme | 20 ++++++++++++- ios/MetaMask/AppDelegate.h | 1 + ios/MetaMask/AppDelegate.m | 3 +- scripts/build.sh | 25 ++++++++++++---- 13 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 ios/GoogleServices/GoogleService-Info-example.plist create mode 100644 ios/GoogleServices/GoogleService-Info.plist diff --git a/.android.env.example b/.android.env.example index 93b4a8c334e..5c769312cca 100644 --- a/.android.env.example +++ b/.android.env.example @@ -9,7 +9,7 @@ export FCM_CONFIG_PROJECT_ID= export FCM_CONFIG_STORAGE_BUCKET= export FCM_CONFIG_MESSAGING_SENDER_ID= export FCM_CONFIG_APP_ID= -export GOOGLE_SERVICES_B64= +export GOOGLE_SERVICES_B64_ANDROID= #Notifications Feature Announcements export FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN= export FEATURES_ANNOUNCEMENTS_SPACE_ID= diff --git a/.gitignore b/.gitignore index 94e55b9bae8..c98f331e0da 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ android/app/_build* # if we ever want to add google services android/app/google-services.json +ios/GoogleService-Info.plist # node.js node_modules/ diff --git a/.ios.env.example b/.ios.env.example index 05aadc9b359..cc449b8b6e1 100644 --- a/.ios.env.example +++ b/.ios.env.example @@ -8,7 +8,7 @@ FCM_CONFIG_PROJECT_ID= FCM_CONFIG_STORAGE_BUCKET= FCM_CONFIG_MESSAGING_SENDER_ID= FCM_CONFIG_APP_ID= -GOOGLE_SERVICES_B64= +GOOGLE_SERVICES_B64_IOS= #Notifications Feature Announcements FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN= FEATURES_ANNOUNCEMENTS_SPACE_ID= diff --git a/.js.env.example b/.js.env.example index 81d9fea44a1..c151b882877 100644 --- a/.js.env.example +++ b/.js.env.example @@ -79,7 +79,8 @@ export FCM_CONFIG_PROJECT_ID="" export FCM_CONFIG_STORAGE_BUCKET="" export FCM_CONFIG_MESSAGING_SENDER_ID="" export FCM_CONFIG_APP_ID="" -export GOOGLE_SERVICES_B64="" +export GOOGLE_SERVICES_B64_ANDROID="" +export GOOGLE_SERVICES_B64_IOS="" #Notifications Feature Announcements export FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN= export FEATURES_ANNOUNCEMENTS_SPACE_ID= diff --git a/README.md b/README.md index 2d19b29c7f8..587898dcbd4 100644 --- a/README.md +++ b/README.md @@ -41,18 +41,24 @@ cd metamask-mobile **Firebase Messaging Setup** -Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` directory as well your `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64` variable depending on the environment you are running the app (ios/android). +Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` or `GoogleService-Info.plist` file in the `ios` directory. In case you don't have FCM account, you can use `./android/app/google-services-example.json` for Android or `./ios/GoogleServices/GoogleService-Info-example.plist` for iOS and follow the steps below to populate the correct environment variables in the `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` variable depending on the environment you are running the app (ios/android). -ATTENTION: In case you don't provide your own Firebase project config file, you can make use of a mock file at `android/app/google-services-example.json`, following the steps below from the root of the project: +The value you should provide to `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` is the base64 encoded version of your Firebase project config file, which can be generated as follows: +**For Android** ```bash -echo "export GOOGLE_SERVICES_B64=\"$(base64 -w0 -i ./android/app/google-services-example.json)\"" | tee -a .js.env .ios.env .android.env +echo "export GOOGLE_SERVICES_B64_ANDROID=\"$(base64 -w0 -i ./android/app/google-services-example.json)\"" | tee -a .js.env .ios.env .android.env ``` -You can make usage of a mock file at `android/app/google-services-example.json`, following the same steps above from the root of the project. +**For iOS** +```bash +echo "export GOOGLE_SERVICES_B64_IOS=\"$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info-example.plist)\"" | tee -a .js.env .ios.env +``` -In case of any doubt, please follow the instructions in the link below to get your Firebase project config file. +[!CAUTION] +> In case you don't provide your own Firebase project config file or run the steps above, you will face the error `No matching client found for package name 'io.metamask'`. +In case of any doubt, please follow the instructions in the link below to get your Firebase project config file. [Firebase Project Quickstart](https://firebaseopensource.com/projects/firebase/quickstart-js/messaging/readme/#getting_started) **Install dependencies** diff --git a/ios/GoogleServices/GoogleService-Info-example.plist b/ios/GoogleServices/GoogleService-Info-example.plist new file mode 100644 index 00000000000..1294630b17d --- /dev/null +++ b/ios/GoogleServices/GoogleService-Info-example.plist @@ -0,0 +1,30 @@ + + + + + API_KEY + mock-api-key-1234 + GCM_SENDER_ID + mock-gcm-sender-id-1234 + PLIST_VERSION + 1 + BUNDLE_ID + io.metamask.MetaMask + PROJECT_ID + mockproject-1234 + STORAGE_BUCKET + mock-storage-bucket-1234.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + mock-google-app-id-1234 + + diff --git a/ios/GoogleServices/GoogleService-Info.plist b/ios/GoogleServices/GoogleService-Info.plist new file mode 100644 index 00000000000..8410def31e2 --- /dev/null +++ b/ios/GoogleServices/GoogleService-Info.plist @@ -0,0 +1,26 @@ + + + + + API_KEY + $(FCM_CONFIG_API_KEY) + GCM_SENDER_ID + $(FCM_CONFIG_MESSAGING_SENDER_ID) + PLIST_VERSION + 1 + BUNDLE_ID + $(PRODUCT_BUNDLE_IDENTIFIER) + PROJECT_ID + $(FCM_CONFIG_PROJECT_ID) + STORAGE_BUCKET + $(FCM_CONFIG_STORAGE_BUCKET) + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + $(FCM_CONFIG_APP_ID) + + diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index 43068635fab..a43d75270e8 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -136,6 +136,9 @@ B339FF3C289ABF2C001B89FB /* MetaMask-QA-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B339FEA72899852C001B89FB /* MetaMask-QA-Info.plist */; }; B638844E306CAE9147B52C85 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; BF39E5BAE0F34F9091FF6AC0 /* EuclidCircularB-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = A8DE9C5BC0714D648276E123 /* EuclidCircularB-Semibold.otf */; }; + C8424AE42CCC01F900F0BEB7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C8424AE32CCC01F900F0BEB7 /* GoogleService-Info.plist */; }; + C8424AE52CCC01F900F0BEB7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C8424AE32CCC01F900F0BEB7 /* GoogleService-Info.plist */; }; + C8424AE62CCC01F900F0BEB7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C8424AE32CCC01F900F0BEB7 /* GoogleService-Info.plist */; }; CD13D926E1E84D9ABFE672C0 /* Roboto-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3E2492C67CF345CABD7B8601 /* Roboto-BlackItalic.ttf */; }; CF9895772A3B49BE00B4C9B5 /* RCTMinimizer.m in Sources */ = {isa = PBXBuildFile; fileRef = CF9895762A3B49BE00B4C9B5 /* RCTMinimizer.m */; }; CF9895782A3B49BE00B4C9B5 /* RCTMinimizer.m in Sources */ = {isa = PBXBuildFile; fileRef = CF9895762A3B49BE00B4C9B5 /* RCTMinimizer.m */; }; @@ -302,6 +305,7 @@ BCC95B62DD6241678CDF73B3 /* CentraNo1-BookItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "CentraNo1-BookItalic.otf"; path = "../app/fonts/CentraNo1-BookItalic.otf"; sourceTree = ""; }; BF485CDA047B4D52852B87F5 /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = ""; }; C752564A28B44392AEE16BD5 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Medium.ttf"; path = "../app/fonts/Roboto-Medium.ttf"; sourceTree = ""; }; + C8424AE32CCC01F900F0BEB7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; C9FD3FB1258A41A5A0546C83 /* Roboto-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-BoldItalic.ttf"; path = "../app/fonts/Roboto-BoldItalic.ttf"; sourceTree = ""; }; CE0434C5FB7C4C6F9FEBDCE2 /* EuclidCircularB-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "EuclidCircularB-Medium.otf"; path = "../app/fonts/EuclidCircularB-Medium.otf"; sourceTree = ""; }; CF014205BB8964CFE74D4D8E /* Pods-MetaMask-QA.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MetaMask-QA.release.xcconfig"; path = "Target Support Files/Pods-MetaMask-QA/Pods-MetaMask-QA.release.xcconfig"; sourceTree = ""; }; @@ -533,6 +537,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + C8424AE32CCC01F900F0BEB7 /* GoogleService-Info.plist */, 2EF283352B17EC4E00D7B4B1 /* Light-Swift-Untar-V2 */, 2EF283312B17EC1A00D7B4B1 /* RNTar.m */, 2EF283292B17EBD600D7B4B1 /* RnTar.swift */, @@ -765,6 +770,7 @@ EF65C42EA15B4774B1947A12 /* Roboto-Medium.ttf in Resources */, DC6A024F56DD43E1A83B47B1 /* Roboto-MediumItalic.ttf in Resources */, 34CEE49BC79D411687B42FA9 /* Roboto-Regular.ttf in Resources */, + C8424AE62CCC01F900F0BEB7 /* GoogleService-Info.plist in Resources */, 7E08FB90F3754D47994208B4 /* Roboto-Thin.ttf in Resources */, 7C0226ABD9694AEDBAF3016F /* Roboto-ThinItalic.ttf in Resources */, 15ACC9FB226555820063978B /* LaunchScreen.xib in Resources */, @@ -819,6 +825,7 @@ 2EF282802B0FF86900D7B4B1 /* EuclidCircularB-BoldItalic.otf in Resources */, 2EF282812B0FF86900D7B4B1 /* EuclidCircularB-Light.otf in Resources */, 2EF282822B0FF86900D7B4B1 /* EuclidCircularB-LightItalic.otf in Resources */, + C8424AE52CCC01F900F0BEB7 /* GoogleService-Info.plist in Resources */, 2EF282832B0FF86900D7B4B1 /* EuclidCircularB-Medium.otf in Resources */, 2EF282842B0FF86900D7B4B1 /* EuclidCircularB-MediumItalic.otf in Resources */, 2EF282852B0FF86900D7B4B1 /* EuclidCircularB-Regular.otf in Resources */, @@ -840,6 +847,7 @@ B339FF15289ABD70001B89FB /* Roboto-BlackItalic.ttf in Resources */, B339FF16289ABD70001B89FB /* Roboto-Bold.ttf in Resources */, B339FF17289ABD70001B89FB /* debug.xcconfig in Resources */, + C8424AE42CCC01F900F0BEB7 /* GoogleService-Info.plist in Resources */, B339FF18289ABD70001B89FB /* Roboto-BoldItalic.ttf in Resources */, B339FF19289ABD70001B89FB /* Roboto-Italic.ttf in Resources */, B339FF1A289ABD70001B89FB /* Roboto-Light.ttf in Resources */, diff --git a/ios/MetaMask.xcodeproj/xcshareddata/xcschemes/MetaMask-QA.xcscheme b/ios/MetaMask.xcodeproj/xcshareddata/xcschemes/MetaMask-QA.xcscheme index c6cf377abfa..85b71282b08 100644 --- a/ios/MetaMask.xcodeproj/xcshareddata/xcschemes/MetaMask-QA.xcscheme +++ b/ios/MetaMask.xcodeproj/xcshareddata/xcschemes/MetaMask-QA.xcscheme @@ -1,10 +1,28 @@ + version = "1.7"> + + + + + + + + + + + version = "1.7"> + + + + + + + + + + #import #import diff --git a/ios/MetaMask/AppDelegate.m b/ios/MetaMask/AppDelegate.m index b22d5678257..e6337175ecd 100644 --- a/ios/MetaMask/AppDelegate.m +++ b/ios/MetaMask/AppDelegate.m @@ -1,4 +1,5 @@ #import "AppDelegate.h" +#import #import #import #import @@ -19,7 +20,7 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ - + [FIRApp configure]; NSString *foxCodeFromBundle = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"fox_code"]; NSString *foxCode; diff --git a/scripts/build.sh b/scripts/build.sh index c56b77fdff9..f1cd9a9ef5b 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -181,6 +181,17 @@ prebuild_ios(){ # Required to install mixpanel dep git submodule update --init --recursive unset PREFIX + # Create GoogleService-Info.plist file to be used by the Firebase services. + # Check if GOOGLE_SERVICES_B64_IOS is set + if [ ! -z "$GOOGLE_SERVICES_B64_IOS" ]; then + echo -n $GOOGLE_SERVICES_B64_IOS | base64 -d > ./ios/GoogleServices/GoogleService-Info.plist + echo "GoogleService-Info.plist has been created successfully." + # Ensure the file has read and write permissions + chmod 664 ./ios/GoogleServices/GoogleService-Info.plist + else + echo "GOOGLE_SERVICES_B64_IOS is not set in the .env file." + exit 1 + fi } prebuild_android(){ @@ -190,13 +201,15 @@ prebuild_android(){ # Copy fonts with iconset yes | cp -rf ./app/fonts/Metamask.ttf ./android/app/src/main/assets/fonts/Metamask.ttf - #Create google-services.json file to be used by the Firebase services. - # Check if GOOGLE_SERVICES_B64 is set - if [ ! -z "$GOOGLE_SERVICES_B64" ]; then - echo -n $GOOGLE_SERVICES_B64 | base64 -d > ./android/app/google-services.json + #Create google-services.json file to be used by the Firebase services. + # Check if GOOGLE_SERVICES_B64_ANDROID is set + if [ ! -z "$GOOGLE_SERVICES_B64_ANDROID" ]; then + echo -n $GOOGLE_SERVICES_B64_ANDROID | base64 -d > ./android/app/google-services.json echo "google-services.json has been created successfully." + # Ensure the file has read and write permissions + chmod 664 ./android/app/google-services.json else - echo "GOOGLE_SERVICES_B64 is not set in the .env file." + echo "GOOGLE_SERVICES_B64_ANDROID is not set in the .env file." exit 1 fi @@ -629,4 +642,4 @@ else else envFileMissing $ANDROID_ENV_FILE fi -fi \ No newline at end of file +fi From e96777ae0ce7b8f8bac584386c87dd0d6745829a Mon Sep 17 00:00:00 2001 From: Simon <9662464+siibars@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:05:00 +0100 Subject: [PATCH 09/90] fix: toBignumber conversion error with high balance (#12010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** There is a bignumber conversion attempt which is failing, this change fixes this. ## **Related issues** Fixes: STAKE-848 ## **Manual testing steps** 1. connect with an account with a high ETH balance 2. enable the native staking feature flag 3. click stake to get to the StakeinputView ## **Screenshots/Recordings** ### **Before** ![image](https://github.com/user-attachments/assets/bd071444-a6b6-49ca-ae31-4339ebcc68e6) View: Root Error: [number-to-bn] while converting number "3.487400189415765903484e+21" to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. ### **After** This issue doesn't happen. ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- app/components/UI/Stake/__mocks__/mockData.ts | 12 +++++ .../UI/Stake/hooks/useBalance.test.tsx | 45 ++++++++++++++----- app/components/UI/Stake/hooks/useBalance.ts | 5 +-- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/app/components/UI/Stake/__mocks__/mockData.ts b/app/components/UI/Stake/__mocks__/mockData.ts index 43762d3eb16..a0b8eed1d8b 100644 --- a/app/components/UI/Stake/__mocks__/mockData.ts +++ b/app/components/UI/Stake/__mocks__/mockData.ts @@ -67,6 +67,18 @@ export const MOCK_GET_POOLED_STAKES_API_RESPONSE: PooledStakes = { exchangeRate: '1.010906701603882254', }; +export const MOCK_GET_POOLED_STAKES_API_RESPONSE_HIGH_ASSETS_AMOUNT: PooledStakes = { + accounts: [ + { + account: '0x0111111111abcdef2222222222abcdef33333333', + lifetimeRewards: '0', + assets: '99999999990000000000000', + exitRequests: [], + }, + ], + exchangeRate: '1.010906701603882254', +}; + export const MOCK_GET_VAULT_RESPONSE: VaultData = { apy: '2.853065141088762750393474836309926', capacity: diff --git a/app/components/UI/Stake/hooks/useBalance.test.tsx b/app/components/UI/Stake/hooks/useBalance.test.tsx index 33bf7cc7903..17c73f1685c 100644 --- a/app/components/UI/Stake/hooks/useBalance.test.tsx +++ b/app/components/UI/Stake/hooks/useBalance.test.tsx @@ -1,9 +1,11 @@ -import { MOCK_GET_POOLED_STAKES_API_RESPONSE } from '../__mocks__/mockData'; +import { MOCK_GET_POOLED_STAKES_API_RESPONSE, MOCK_GET_POOLED_STAKES_API_RESPONSE_HIGH_ASSETS_AMOUNT } from '../__mocks__/mockData'; import { createMockAccountsControllerState } from '../../../../util/test/accountsControllerTestUtils'; import { backgroundState } from '../../../../util/test/initial-root-state'; import { renderHookWithProvider } from '../../../../util/test/renderWithProvider'; import useBalance from './useBalance'; import { toHex } from '@metamask/controller-utils'; +import usePooledStakes from './usePooledStakes'; +import { PooledStake } from '@metamask/stake-sdk'; const MOCK_ADDRESS_1 = '0x0'; @@ -35,15 +37,12 @@ const initialState = { }, }; -const mockPooledStakeData = MOCK_GET_POOLED_STAKES_API_RESPONSE.accounts[0]; -const mockExchangeRate = MOCK_GET_POOLED_STAKES_API_RESPONSE.exchangeRate; - -jest.mock('../hooks/usePooledStakes', () => ({ - __esModule: true, - default: () => ({ - pooledStakesData: mockPooledStakeData, - exchangeRate: mockExchangeRate, - loading: false, +jest.mock('../hooks/usePooledStakes'); +const mockUsePooledStakes = (pooledStake: PooledStake, exchangeRate: string) => { + (usePooledStakes as jest.MockedFn).mockReturnValue({ + pooledStakesData: pooledStake, + exchangeRate, + isLoadingPooledStakesData: false, error: null, refreshPooledStakes: jest.fn(), hasStakedPositions: true, @@ -51,8 +50,8 @@ jest.mock('../hooks/usePooledStakes', () => ({ hasNeverStaked: false, hasRewards: true, hasRewardsOnly: false, - }), -})); + }); +}; describe('useBalance', () => { afterEach(() => { @@ -64,10 +63,12 @@ describe('useBalance', () => { }); it('returns balance and fiat values based on account and pooled stake data', async () => { + mockUsePooledStakes(MOCK_GET_POOLED_STAKES_API_RESPONSE.accounts[0], MOCK_GET_POOLED_STAKES_API_RESPONSE.exchangeRate); const { result } = renderHookWithProvider(() => useBalance(), { state: initialState, }); + expect(result.current.balance).toBe('12345678.90988'); // ETH balance expect(result.current.balanceWei.toString()).toBe( '12345678909876543210000000', @@ -81,6 +82,7 @@ describe('useBalance', () => { }); it('returns default values when no selected address and no account data', async () => { + mockUsePooledStakes(MOCK_GET_POOLED_STAKES_API_RESPONSE.accounts[0], MOCK_GET_POOLED_STAKES_API_RESPONSE.exchangeRate); const { result } = renderHookWithProvider(() => useBalance(), { state: { ...initialState, @@ -106,4 +108,23 @@ describe('useBalance', () => { expect(result.current.balanceFiat).toBe('$0.00'); // Fiat balance expect(result.current.balanceFiatNumber).toBe(0); // Fiat number balance }); + + it('returns correct stake amounts and fiat values based on account with high amount of assets', async () => { + mockUsePooledStakes(MOCK_GET_POOLED_STAKES_API_RESPONSE_HIGH_ASSETS_AMOUNT.accounts[0], MOCK_GET_POOLED_STAKES_API_RESPONSE_HIGH_ASSETS_AMOUNT.exchangeRate); + const { result } = renderHookWithProvider(() => useBalance(), { + state: initialState, + }); + + expect(result.current.balance).toBe('12345678.90988'); // ETH balance + expect(result.current.balanceWei.toString()).toBe( + '12345678909876543210000000', + ); + expect(result.current.balanceFiat).toBe('$39506172511.60'); // Fiat balance + expect(result.current.balanceFiatNumber).toBe(39506172511.6); // Fiat number balance + + expect(result.current.stakedBalanceWei).toBe('99999999990000000000000'); // No staked assets + expect(result.current.formattedStakedBalanceETH).toBe('99999.99999 ETH'); // Formatted ETH balance + expect(result.current.stakedBalanceFiatNumber).toBe(319999999.968); // Staked balance in fiat number + expect(result.current.formattedStakedBalanceFiat).toBe('$319999999.97'); // + }); }); diff --git a/app/components/UI/Stake/hooks/useBalance.ts b/app/components/UI/Stake/hooks/useBalance.ts index a96c9b6b39b..239e58e4c93 100644 --- a/app/components/UI/Stake/hooks/useBalance.ts +++ b/app/components/UI/Stake/hooks/useBalance.ts @@ -50,8 +50,7 @@ const useBalance = () => { ); const { pooledStakesData } = usePooledStakes(); - const assets = pooledStakesData.assets ?? 0; - + const assets = hexToBN(pooledStakesData.assets).toString('hex'); const formattedStakedBalanceETH = useMemo( () => `${renderFromWei(assets)} ETH`, [assets], @@ -72,7 +71,7 @@ const useBalance = () => { balanceFiat, balanceWei, balanceFiatNumber, - stakedBalanceWei: assets, + stakedBalanceWei: assets ?? '0', formattedStakedBalanceETH, stakedBalanceFiatNumber, formattedStakedBalanceFiat, From 1b875f478aa5816393f0ba8dba450da01b2ae1a6 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:09:07 +0000 Subject: [PATCH 10/90] chore: add new copying for PN messages (#12046) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR aims to implement a new wording/message to be presented to our users while receiving Push Notification messages. ## **Related issues** Fixes: [NOTIFY-1267](https://consensyssoftware.atlassian.net/browse/NOTIFY-1267?atlOrigin=eyJpIjoiYmVhMDdjNTEwNGJmNDRhYmE5MjQxNjFlMWE0MThlOWYiLCJwIjoiaiJ9) ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [NOTIFY-1267]: https://consensyssoftware.atlassian.net/browse/NOTIFY-1267?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- locales/languages/en.json | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/locales/languages/en.json b/locales/languages/en.json index 9c7273b8fbf..e796d25b37c 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -2215,6 +2215,38 @@ "cancelled_message": "Tap to view this transaction", "received_message": "Tap to view this transaction", "received_payment_message": "You received {{amount}} DAI", + "push_notification_content": { + "metamask_swap_completed_title": "Swap completed", + "metamask_swap_completed_description": "Your MetaMask Swap was successful", + "erc20_sent_title": "Funds sent", + "erc20_sent_description": "You successfully sent {{amount}} {{token}}", + "erc20_received_title": "Funds received", + "erc20_received_description": "You received {{amount}} {{token}}", + "eth_sent_title": "Funds sent", + "eth_sent_description": "You successfully sent {{amount}} ETH", + "eth_received_title": "Funds received", + "eth_received_description": "You received {{amount}} {{token}}", + "rocketpool_stake_completed_title": "Stake complete", + "rocketpool_stake_completed_description": "Your RocketPool stake was successful", + "rocketpool_unstake_completed_title": "Unstake complete", + "rocketpool_unstake_completed_description": "Your RocketPool unstake was successful", + "lido_stake_completed_title": "Stake complete", + "lido_stake_completed_description": "Your Lido stake was successful", + "lido_withdrawal_requested_title": "Withdrawal requested", + "lido_withdrawal_requested_description": "Your Lido withdrawal request was submitted", + "lido_withdrawal_completed_title": "Withdrawal completed", + "lido_withdrawal_completed_description": "Your Lido withdrawal was successful", + "lido_stake_ready_to_be_withdrawn_title": "Stake ready for withdrawal ", + "lido_stake_ready_to_be_withdrawn_description": "Your Lido stake is now ready to be withdrawn", + "erc721_sent_title": "NFT sent", + "erc721_sent_description": "You've successfully sent an NFT", + "erc721_received_title": "NFT received", + "erc721_received_description": "You received a new NFT", + "erc1155_sent_title": "NFT sent", + "erc1155_sent_description": "You've successfully sent an NFT", + "erc1155_received_title": "NFT received", + "erc1155_received_description": "You received a new NFT" + }, "prompt_title": "Receive Push Notifications", "notifications_enabled_error_title": "Something went wrong", "notifications_enabled_error_desc": "We couldn't enable notifications. Please try again later.", From e49c6ba280a53d2e167b08de7623554e524717ae Mon Sep 17 00:00:00 2001 From: tommasini <46944231+tommasini@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:05:31 +0000 Subject: [PATCH 11/90] fix: re renders of wallet view on every navigation action (#12002) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Wallet view was re rendering on every navigation action. ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/b544a97a-030f-4aea-b67e-cf954546d85e ### **After** https://github.com/user-attachments/assets/9bd50499-89f5-4ae9-a858-4c9648778716 ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../SecuritySettings/SecuritySettings.tsx | 29 ++++-- app/components/Views/Wallet/index.tsx | 81 ++++------------ .../hooks/useCheckMultiRpcModal/index.ts | 1 + .../useCheckMultiRpcModal.test.ts | 93 +++++++++++++++++++ .../useCheckMultiRpcModal.ts | 38 ++++++++ .../useCheckNftAutoDetectionModal/index.ts | 1 + .../useCheckNftAutoDetectionModal.test.ts | 76 +++++++++++++++ .../useCheckNftAutoDetectionModal.ts | 42 +++++++++ 8 files changed, 288 insertions(+), 73 deletions(-) create mode 100644 app/components/hooks/useCheckMultiRpcModal/index.ts create mode 100644 app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.test.ts create mode 100644 app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.ts create mode 100644 app/components/hooks/useCheckNftAutoDetectionModal/index.ts create mode 100644 app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.test.ts create mode 100644 app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.ts diff --git a/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx b/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx index df3b897cc95..2f2da43d0dd 100644 --- a/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx +++ b/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx @@ -91,6 +91,8 @@ import IPFSGatewaySettings from '../../Settings/IPFSGatewaySettings'; import IncomingTransactionsSettings from '../../Settings/IncomingTransactionsSettings'; import BatchAccountBalanceSettings from '../../Settings/BatchAccountBalanceSettings'; import { isNotificationsFeatureEnabled } from '../../../../util/notifications'; +import useCheckNftAutoDetectionModal from '../../../hooks/useCheckNftAutoDetectionModal'; +import useCheckMultiRpcModal from '../../../hooks/useCheckMultiRpcModal'; const Heading: React.FC = ({ children, first }) => { const { colors } = useTheme(); @@ -136,13 +138,12 @@ const Settings: React.FC = () => { loading: disableNotificationsLoading, error: disableNotificationsError, } = useDisableNotifications(); - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const browserHistory = useSelector((state: any) => state.browser.history); - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const lockTime = useSelector((state: any) => state.settings.lockTime); + const browserHistory = useSelector( + (state: RootState) => state.browser.history, + ); + + const lockTime = useSelector((state: RootState) => state.settings.lockTime); const useTransactionSimulations = useSelector( selectUseTransactionSimulations, ); @@ -152,11 +153,21 @@ const Settings: React.FC = () => { ); const seedphraseBackedUp = useSelector( - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (state: any) => state.user.seedphraseBackedUp, + (state: RootState) => state.user.seedphraseBackedUp, ); + + /** + * Shows Nft auto detect modal if the user is on mainnet, never saw the modal and have nft detection off + */ + useCheckNftAutoDetectionModal(); + + /** + * Show multi rpc modal if there are networks duplicated and if never showed before + */ + useCheckMultiRpcModal(); + const type = useSelector(selectProviderType); + const isMainnet = type === MAINNET; const updateNavBar = useCallback(() => { diff --git a/app/components/Views/Wallet/index.tsx b/app/components/Views/Wallet/index.tsx index 83f3b25629d..4ecc384baa6 100644 --- a/app/components/Views/Wallet/index.tsx +++ b/app/components/Views/Wallet/index.tsx @@ -16,7 +16,7 @@ import { AppStateStatus, } from 'react-native'; import type { Theme } from '@metamask/design-tokens'; -import { connect, useDispatch, useSelector } from 'react-redux'; +import { connect, useSelector } from 'react-redux'; import ScrollableTabView from 'react-native-scrollable-tab-view'; import DefaultTabBar from 'react-native-scrollable-tab-view/DefaultTabBar'; import { baseStyles } from '../../../styles/common'; @@ -49,7 +49,6 @@ import Routes from '../../../constants/navigation/Routes'; import { getDecimalChainId, getIsNetworkOnboarded, - isMainNet, } from '../../../util/networks'; import { selectChainId, @@ -82,19 +81,10 @@ import { RootState } from '../../../reducers'; import usePrevious from '../../hooks/usePrevious'; import { selectSelectedInternalAccountChecksummedAddress } from '../../../selectors/accountsController'; import { selectAccountBalanceByChainId } from '../../../selectors/accountTrackerController'; -import { - selectShowMultiRpcModal, - selectUseNftDetection, -} from '../../../selectors/preferencesController'; -import { - setNftAutoDetectionModalOpen, - setMultiRpcMigrationModalOpen, -} from '../../../actions/security'; import { hideNftFetchingLoadingIndicator as hideNftFetchingLoadingIndicatorAction, showNftFetchingLoadingIndicator as showNftFetchingLoadingIndicatorAction, } from '../../../reducers/collectibles'; -import { getCurrentRoute } from '../../../reducers/navigation'; import { WalletViewSelectorsIDs } from '../../../../e2e/selectors/wallet/WalletView.selectors'; import { getMetamaskNotificationsUnreadCount, @@ -105,7 +95,8 @@ import { import { ButtonVariants } from '../../../component-library/components/Buttons/Button'; import { useListNotifications } from '../../../util/notifications/hooks/useNotifications'; import { PortfolioBalance } from '../../UI/Tokens/TokenList/PortfolioBalance'; -import { isObject } from 'lodash'; +import useCheckNftAutoDetectionModal from '../../hooks/useCheckNftAutoDetectionModal'; +import useCheckMultiRpcModal from '../../hooks/useCheckMultiRpcModal'; const createStyles = ({ colors, typography }: Theme) => StyleSheet.create({ @@ -163,7 +154,6 @@ const Wallet = ({ navigation, storePrivacyPolicyShownDate, shouldShowNewPrivacyToast, - currentRouteName, storePrivacyPolicyClickedOrClosed, showNftFetchingLoadingIndicator, hideNftFetchingLoadingIndicator, @@ -177,7 +167,7 @@ const Wallet = ({ const { trackEvent } = useMetrics(); const styles = createStyles(theme); const { colors } = theme; - const dispatch = useDispatch(); + const networkConfigurations = useSelector(selectNetworkConfigurations); /** @@ -292,9 +282,7 @@ const Wallet = ({ * Network onboarding state */ const networkOnboardingState = useSelector( - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (state: any) => state.networkOnboarded.networkOnboardedState, + (state: RootState) => state.networkOnboarded.networkOnboardedState, ); const isNotificationEnabled = useSelector( @@ -314,11 +302,15 @@ const Wallet = ({ const networkName = networkConfigurations?.[chainId]?.name ?? name; const networkImageSource = useSelector(selectNetworkImageSource); - const useNftDetection = useSelector(selectUseNftDetection); - const showMultiRpcModal = useSelector(selectShowMultiRpcModal); - const isNFTAutoDetectionModalViewed = useSelector( - (state: RootState) => state.security.isNFTAutoDetectionModalViewed, - ); + /** + * Shows Nft auto detect modal if the user is on mainnet, never saw the modal and have nft detection off + */ + useCheckNftAutoDetectionModal(); + + /** + * Show multi rpc modal if there are networks duplicated and if never showed before + */ + useCheckMultiRpcModal(); /** * Callback to trigger when pressing the navigation title. @@ -332,47 +324,10 @@ const Wallet = ({ }); }, [navigate, providerConfig.chainId, trackEvent]); - const isNetworkDuplicated = Object.values(networkConfigurations).some( - (networkConfiguration) => - isObject(networkConfiguration) && - Array.isArray(networkConfiguration.rpcEndpoints) && - networkConfiguration.rpcEndpoints.length > 1, - ); - - const checkNftAutoDetectionModal = useCallback(() => { - const isOnMainnet = isMainNet(providerConfig.chainId); - if (!useNftDetection && isOnMainnet && !isNFTAutoDetectionModalViewed) { - navigation.navigate(Routes.MODAL.ROOT_MODAL_FLOW, { - screen: Routes.MODAL.NFT_AUTO_DETECTION_MODAL, - }); - dispatch(setNftAutoDetectionModalOpen(true)); - } - }, [ - dispatch, - isNFTAutoDetectionModalViewed, - navigation, - providerConfig.chainId, - useNftDetection, - ]); - - const checkMultiRpcModal = useCallback(() => { - if (showMultiRpcModal && isNetworkDuplicated) { - navigation.navigate(Routes.MODAL.ROOT_MODAL_FLOW, { - screen: Routes.MODAL.MULTI_RPC_MIGRATION_MODAL, - }); - dispatch(setMultiRpcMigrationModalOpen(true)); - } - }, [dispatch, showMultiRpcModal, navigation, isNetworkDuplicated]); - + /** + * Check to see if notifications are enabled + */ useEffect(() => { - if ( - currentRouteName === 'Wallet' || - currentRouteName === 'SecuritySettings' - ) { - checkNftAutoDetectionModal(); - checkMultiRpcModal(); - } - async function checkIfNotificationsAreEnabled() { await NotificationsService.isDeviceNotificationEnabled(); } @@ -432,7 +387,6 @@ const Wallet = ({ providerConfig.rpcUrl, networkOnboardingState, prevChainId, - checkNftAutoDetectionModal, accountBalanceByChainId?.balance, ]); @@ -679,7 +633,6 @@ const Wallet = ({ // eslint-disable-next-line @typescript-eslint/no-explicit-any const mapStateToProps = (state: any) => ({ shouldShowNewPrivacyToast: shouldShowNewPrivacyToastSelector(state), - currentRouteName: getCurrentRoute(state), }); // TODO: Replace "any" with type diff --git a/app/components/hooks/useCheckMultiRpcModal/index.ts b/app/components/hooks/useCheckMultiRpcModal/index.ts new file mode 100644 index 00000000000..f012ddb4024 --- /dev/null +++ b/app/components/hooks/useCheckMultiRpcModal/index.ts @@ -0,0 +1 @@ +export { default } from './useCheckMultiRpcModal'; diff --git a/app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.test.ts b/app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.test.ts new file mode 100644 index 00000000000..a0ca6797db8 --- /dev/null +++ b/app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.test.ts @@ -0,0 +1,93 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { useDispatch, useSelector } from 'react-redux'; +import { useNavigation } from '@react-navigation/native'; +import useCheckMultiRpcModal from './useCheckMultiRpcModal'; +import { setMultiRpcMigrationModalOpen } from '../../../actions/security'; +import Routes from '../../../constants/navigation/Routes'; +import { isObject } from '@metamask/utils'; +import { selectShowMultiRpcModal } from '../../../selectors/preferencesController'; +import { selectNetworkConfigurations } from '../../../selectors/networkController'; + +// Mock the necessary modules +jest.mock('react-redux', () => ({ + useDispatch: jest.fn(), + useSelector: jest.fn(), +})); + +jest.mock('@react-navigation/native', () => ({ + useNavigation: jest.fn(), +})); + +jest.mock('@metamask/utils', () => ({ + isObject: jest.fn(), +})); + +jest.mock('../../../selectors/preferencesController', () => ({ + selectShowMultiRpcModal: jest.fn(), +})); + +jest.mock('../../../selectors/networkController', () => ({ + selectNetworkConfigurations: jest.fn(), +})); + +describe('useCheckMultiRpcModal', () => { + const dispatchMock = jest.fn(); + const navigateMock = jest.fn(); + + beforeEach(() => { + (useDispatch as jest.Mock).mockReturnValue(dispatchMock); + (useNavigation as jest.Mock).mockReturnValue({ navigate: navigateMock }); + (useSelector as jest.Mock).mockImplementation((selector) => { + switch (selector) { + case selectShowMultiRpcModal: + return true; + case selectNetworkConfigurations: + return { + network1: { rpcEndpoints: ['https://rpc1', 'https://rpc2'] }, + network2: { rpcEndpoints: ['https://rpc3'] }, + }; + default: + return false; + } + }); + (isObject as unknown as jest.Mock).mockImplementation( + (obj) => typeof obj === 'object' && obj !== null, + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should navigate and dispatch action when conditions are met', () => { + renderHook(() => useCheckMultiRpcModal()); + + expect(navigateMock).toHaveBeenCalledWith(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.MODAL.MULTI_RPC_MIGRATION_MODAL, + }); + expect(dispatchMock).toHaveBeenCalledWith( + setMultiRpcMigrationModalOpen(true), + ); + }); + + it('should not navigate or dispatch action when conditions are not met', () => { + (useSelector as jest.Mock).mockImplementation((selector) => { + switch (selector) { + case selectShowMultiRpcModal: + return false; + case selectNetworkConfigurations: + return { + network1: { rpcEndpoints: ['https://rpc1'] }, + network2: { rpcEndpoints: ['https://rpc3'] }, + }; + default: + return false; + } + }); + + renderHook(() => useCheckMultiRpcModal()); + + expect(navigateMock).not.toHaveBeenCalled(); + expect(dispatchMock).not.toHaveBeenCalled(); + }); +}); diff --git a/app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.ts b/app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.ts new file mode 100644 index 00000000000..f2aac04e542 --- /dev/null +++ b/app/components/hooks/useCheckMultiRpcModal/useCheckMultiRpcModal.ts @@ -0,0 +1,38 @@ +import { useCallback, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useNavigation } from '@react-navigation/native'; +import { isObject } from '@metamask/utils'; +import Routes from '../../../constants/navigation/Routes'; +import { setMultiRpcMigrationModalOpen } from '../../../actions/security'; +import { selectShowMultiRpcModal } from '../../../selectors/preferencesController'; +import { selectNetworkConfigurations } from '../../../selectors/networkController'; + +const useCheckMultiRpcModal = () => { + const dispatch = useDispatch(); + const navigation = useNavigation(); + const networkConfigurations = useSelector(selectNetworkConfigurations); + + const showMultiRpcModal = useSelector(selectShowMultiRpcModal); + + const isNetworkDuplicated = Object.values(networkConfigurations).some( + (networkConfiguration) => + isObject(networkConfiguration) && + Array.isArray(networkConfiguration.rpcEndpoints) && + networkConfiguration.rpcEndpoints.length > 1, + ); + + const checkMultiRpcModal = useCallback(() => { + if (showMultiRpcModal && isNetworkDuplicated) { + navigation.navigate(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.MODAL.MULTI_RPC_MIGRATION_MODAL, + }); + dispatch(setMultiRpcMigrationModalOpen(true)); + } + }, [dispatch, showMultiRpcModal, navigation, isNetworkDuplicated]); + + useEffect(() => { + checkMultiRpcModal(); + }, [checkMultiRpcModal]); +}; + +export default useCheckMultiRpcModal; diff --git a/app/components/hooks/useCheckNftAutoDetectionModal/index.ts b/app/components/hooks/useCheckNftAutoDetectionModal/index.ts new file mode 100644 index 00000000000..72c92ca8dc6 --- /dev/null +++ b/app/components/hooks/useCheckNftAutoDetectionModal/index.ts @@ -0,0 +1 @@ +export { default } from './useCheckNftAutoDetectionModal'; diff --git a/app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.test.ts b/app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.test.ts new file mode 100644 index 00000000000..94ec9e7afa6 --- /dev/null +++ b/app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.test.ts @@ -0,0 +1,76 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { useDispatch, useSelector } from 'react-redux'; +import { useNavigation } from '@react-navigation/native'; +import useCheckNftAutoDetectionModal from './useCheckNftAutoDetectionModal'; +import { setNftAutoDetectionModalOpen } from '../../../actions/security'; +import Routes from '../../../constants/navigation/Routes'; +import { isMainNet } from '../../../util/networks'; +import { selectUseNftDetection } from '../../../selectors/preferencesController'; +import { selectProviderConfig } from '../../../selectors/networkController'; + +// Mock the necessary modules +jest.mock('react-redux', () => ({ + useDispatch: jest.fn(), + useSelector: jest.fn(), +})); + +jest.mock('@react-navigation/native', () => ({ + useNavigation: jest.fn(), +})); + +jest.mock('../../../util/networks', () => ({ + isMainNet: jest.fn(), +})); + +jest.mock('../../../selectors/preferencesController', () => ({ + selectUseNftDetection: jest.fn(), +})); + +jest.mock('../../../selectors/networkController', () => ({ + selectProviderConfig: jest.fn(), +})); + +describe('useCheckNftAutoDetectionModal', () => { + const dispatchMock = jest.fn(); + const navigateMock = jest.fn(); + + beforeEach(() => { + (useDispatch as jest.Mock).mockReturnValue(dispatchMock); + (useNavigation as jest.Mock).mockReturnValue({ navigate: navigateMock }); + (useSelector as jest.Mock).mockImplementation((selector) => { + switch (selector) { + case selectUseNftDetection: + return false; + case selectProviderConfig: + return { chainId: '1' }; + default: + return false; + } + }); + (isMainNet as jest.Mock).mockReturnValue(true); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should navigate and dispatch action when conditions are met', () => { + renderHook(() => useCheckNftAutoDetectionModal()); + + expect(navigateMock).toHaveBeenCalledWith(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.MODAL.NFT_AUTO_DETECTION_MODAL, + }); + expect(dispatchMock).toHaveBeenCalledWith( + setNftAutoDetectionModalOpen(true), + ); + }); + + it('should not navigate or dispatch action when conditions are not met', () => { + (isMainNet as jest.Mock).mockReturnValue(false); + + renderHook(() => useCheckNftAutoDetectionModal()); + + expect(navigateMock).not.toHaveBeenCalled(); + expect(dispatchMock).not.toHaveBeenCalled(); + }); +}); diff --git a/app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.ts b/app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.ts new file mode 100644 index 00000000000..55eb3e67f2b --- /dev/null +++ b/app/components/hooks/useCheckNftAutoDetectionModal/useCheckNftAutoDetectionModal.ts @@ -0,0 +1,42 @@ +import { useCallback, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useNavigation } from '@react-navigation/native'; + +import { selectUseNftDetection } from '../../../selectors/preferencesController'; +import { isMainNet } from '../../../util/networks'; +import Routes from '../../../constants/navigation/Routes'; +import { setNftAutoDetectionModalOpen } from '../../../actions/security'; +import { RootState } from '../../../reducers'; +import { selectProviderConfig } from '../../../selectors/networkController'; + +const useCheckNftAutoDetectionModal = () => { + const dispatch = useDispatch(); + const navigation = useNavigation(); + const useNftDetection = useSelector(selectUseNftDetection); + const providerConfig = useSelector(selectProviderConfig); + const isNFTAutoDetectionModalViewed = useSelector( + (state: RootState) => state.security.isNFTAutoDetectionModalViewed, + ); + + const checkNftAutoDetectionModal = useCallback(() => { + const isOnMainnet = isMainNet(providerConfig.chainId); + if (!useNftDetection && isOnMainnet && !isNFTAutoDetectionModalViewed) { + navigation.navigate(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.MODAL.NFT_AUTO_DETECTION_MODAL, + }); + dispatch(setNftAutoDetectionModalOpen(true)); + } + }, [ + dispatch, + isNFTAutoDetectionModalViewed, + navigation, + providerConfig.chainId, + useNftDetection, + ]); + + useEffect(() => { + checkNftAutoDetectionModal(); + }, [checkNftAutoDetectionModal]); +}; + +export default useCheckNftAutoDetectionModal; From 87e0c7d863bbd803e75cfb027465bc6d71147dd3 Mon Sep 17 00:00:00 2001 From: Curtis David Date: Mon, 28 Oct 2024 14:59:17 -0400 Subject: [PATCH 12/90] test: move terms of use out of qurantine (#12021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The Purpose of this task is to readd the terms of use e2e to the regression tag. The test failed because of an outdated selector ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../term-of-use.spec.js} | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) rename e2e/specs/{quarantine/term-of-use.broken.js => onboarding/term-of-use.spec.js} (92%) diff --git a/e2e/specs/quarantine/term-of-use.broken.js b/e2e/specs/onboarding/term-of-use.spec.js similarity index 92% rename from e2e/specs/quarantine/term-of-use.broken.js rename to e2e/specs/onboarding/term-of-use.spec.js index 6471add8a6a..8fe2e3355cd 100644 --- a/e2e/specs/quarantine/term-of-use.broken.js +++ b/e2e/specs/onboarding/term-of-use.spec.js @@ -5,10 +5,12 @@ import OnboardingView from '../../pages/Onboarding/OnboardingView'; import MetaMetricsOptIn from '../../pages/Onboarding/MetaMetricsOptInView'; import ImportWalletView from '../../pages/Onboarding/ImportWalletView'; import Assertions from '../../utils/Assertions'; +import { Regression } from '../../tags'; -describe('Term of service', () => { - beforeEach(() => { - jest.setTimeout(200000); +describe(Regression('Term of Use Modal'), () => { + beforeAll(async () => { + jest.setTimeout(150000); + await device.launchApp(); }); it('should displayed Term of Use when first launching app', async () => { @@ -18,7 +20,6 @@ describe('Term of service', () => { await Assertions.checkIfVisible(OnboardingView.container); await OnboardingView.tapImportWalletFromSeedPhrase(); - await Assertions.checkIfVisible(OnboardingCarouselView.container); await MetaMetricsOptIn.tapAgreeButton(); await Assertions.checkIfVisible(TermsOfUseModal.container); }); From a2de45b7de2e044d65f96ed40ed73c5da67438f2 Mon Sep 17 00:00:00 2001 From: Bryan Fullam Date: Mon, 28 Oct 2024 20:19:59 +0100 Subject: [PATCH 13/90] refactor: replace swap slider with swap button (#12030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Feedback was received suggesting that the "swipe to swap" UI was often navigating back instead of executing the swap. This PR replaces the swipe with a button to address this issue and simplify the interaction. ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to the swap page 2. Get quotes 3. See swap button ## **Screenshots/Recordings** ### **Before** Screenshot 2024-10-25 at 17 22 47 ### **After** Screenshot 2024-10-25 at 17 24 04 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/components/UI/Swaps/QuotesView.js | 31 ++++++++------------------- locales/languages/en.json | 2 +- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/app/components/UI/Swaps/QuotesView.js b/app/components/UI/Swaps/QuotesView.js index 47b02c0ad94..431857e6a4c 100644 --- a/app/components/UI/Swaps/QuotesView.js +++ b/app/components/UI/Swaps/QuotesView.js @@ -56,7 +56,6 @@ import ScreenView from '../../Base/ScreenView'; import Text from '../../Base/Text'; import Alert, { AlertType } from '../../Base/Alert'; import StyledButton from '../StyledButton'; -import SliderButton from '../SliderButton'; import LoadingAnimation from './components/LoadingAnimation'; import TokenIcon from './components/TokenIcon'; @@ -444,6 +443,7 @@ function SwapsQuotesView({ const [trackedError, setTrackedError] = useState(false); const [animateOnGasChange, setAnimateOnGasChange] = useState(false); const [isAnimating, setIsAnimating] = useState(false); + const [isHandlingSwap, setIsHandlingSwap] = useState(false); const [multiLayerL1ApprovalFeeTotal, setMultiLayerL1ApprovalFeeTotal] = useState(null); @@ -460,8 +460,6 @@ function SwapsQuotesView({ const [customGasEstimate, setCustomGasEstimate] = useState(null); const [customGasLimit, setCustomGasLimit] = useState(null); - const [isSwiping, setIsSwiping] = useState(false); - // TODO: use this variable in the future when calculating savings const [isSaving] = useState(false); const [isInFetch, setIsInFetch] = useState(false); @@ -1072,7 +1070,10 @@ function SwapsQuotesView({ ); const handleCompleteSwap = useCallback(async () => { + setIsHandlingSwap(true); + if (!selectedQuote) { + setIsHandlingSwap(false); return; } @@ -1088,6 +1089,7 @@ function SwapsQuotesView({ ); if (isHardwareAddress) { + setIsHandlingSwap(false); navigation.dangerouslyGetParent()?.pop(); return; } @@ -1100,6 +1102,7 @@ function SwapsQuotesView({ await handleSwapTransaction(approvalTransactionMetaId); } + setIsHandlingSwap(false); navigation.dangerouslyGetParent()?.pop(); }, [ selectedQuote, @@ -1720,7 +1723,6 @@ function SwapsQuotesView({ contentContainerStyle={styles.screen} style={styles.container} keyboardShouldPersistTaps="handled" - scrollEnabled={!isSwiping} > {(!hasEnoughTokenBalance || !hasEnoughEthBalance) && ( @@ -2155,24 +2157,9 @@ function SwapsQuotesView({ )} - - {`${strings('swaps.swipe_to')} `} - - {strings('swaps.swap')} - - - } - onSwipeChange={setIsSwiping} - completeText={ - - {strings('swaps.completed_swap')} - - } - disabled={unableToSwap || isAnimating} - onComplete={handleCompleteSwap} - /> + + {strings('swaps.swap')} + {strings('swaps.terms_of_service')} diff --git a/locales/languages/en.json b/locales/languages/en.json index e796d25b37c..5320afc6754 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -2777,7 +2777,7 @@ "tap_to_swap": "Tap to Swap", "swipe_to_swap": "Swipe to swap", "swipe_to": "Swipe to", - "swap": "swap", + "swap": "Swap", "completed_swap": "Swap!", "metamask_swap_fee": "MetaMask Swap fee", "fee_text": { From f4163284b27823dd759a36c0fe079baf825820b3 Mon Sep 17 00:00:00 2001 From: Curtis David Date: Mon, 28 Oct 2024 15:26:20 -0400 Subject: [PATCH 14/90] test: Move portfolio connect out of quarantine (#12023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The Purpose of this task is to readd the portfolio connect e2e to the regression tag. ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Co-authored-by: Aslau Mario-Daniel --- .../portfolio-connect-account.spec.js} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename e2e/specs/{quarantine/portfolio-connect-account.failing.js => wallet/portfolio-connect-account.spec.js} (96%) diff --git a/e2e/specs/quarantine/portfolio-connect-account.failing.js b/e2e/specs/wallet/portfolio-connect-account.spec.js similarity index 96% rename from e2e/specs/quarantine/portfolio-connect-account.failing.js rename to e2e/specs/wallet/portfolio-connect-account.spec.js index 70bf066fa6b..12c14a259f7 100644 --- a/e2e/specs/quarantine/portfolio-connect-account.failing.js +++ b/e2e/specs/wallet/portfolio-connect-account.spec.js @@ -1,5 +1,5 @@ 'use strict'; -import { SmokeCore } from '../../tags'; +import { Regression } from '../../tags'; import TabBarComponent from '../../pages/TabBarComponent'; import { loginToApp } from '../../viewHelper'; import { @@ -17,7 +17,7 @@ import PortfolioHomePage from '../../pages/Browser/PortfolioHomePage'; import Assertions from '../../utils/Assertions'; import ConnectModal from '../../pages/modals/ConnectModal'; const fixtureServer = new FixtureServer(); -describe(SmokeCore('Connect account to Portfolio'), () => { +describe(Regression('Connect account to Portfolio'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder().withKeyringController().build(); From d1a58ab562dec4b88e7277b5a2ead8b961a73fc2 Mon Sep 17 00:00:00 2001 From: Mpendulo Ndlovu Date: Mon, 28 Oct 2024 22:16:08 +0200 Subject: [PATCH 15/90] fix: validate chain before send (#12048) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR validates the chain id before handling the deeplink for making an ethereum send. ## **Related issues** Fixes: [11966](https://github.com/MetaMask/metamask-mobile/issues/11966) ## **Manual testing steps** 1. Open the deeplink https://metamask.app.link/send/0x2990079bcdEe240329a520d2444386FC119da21a@56?value=3e18 2. Ensure that BNB is not added as a chain on the wallet 3. You should see an error "Unable to find network with chain id" ## **Screenshots/Recordings** https://github.com/user-attachments/assets/c790fcdc-7737-4718-b5b5-f117151ea0a2 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../Handlers/switchNetwork.test.ts | 10 +++++----- .../DeeplinkManager/Handlers/switchNetwork.ts | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/core/DeeplinkManager/Handlers/switchNetwork.test.ts b/app/core/DeeplinkManager/Handlers/switchNetwork.test.ts index e65f86c3946..d6e6430c1d7 100644 --- a/app/core/DeeplinkManager/Handlers/switchNetwork.test.ts +++ b/app/core/DeeplinkManager/Handlers/switchNetwork.test.ts @@ -44,13 +44,13 @@ describe('switchNetwork', () => { ); }); - it('should not dispatch an alert for an invalid switchToChainId', () => { - const switchToChainId = 'invalid_chain_id' as `${number}` | undefined; + it('should throw an error for an invalid switchToChainId', () => { + const switchToChainId = '56' as `${number}` | undefined; mockHandleNetworkSwitch.mockReturnValue(undefined); - switchNetwork({ deeplinkManager, switchToChainId }); - - expect(deeplinkManager.dispatch).not.toHaveBeenCalled(); + expect(() => switchNetwork({ deeplinkManager, switchToChainId })).toThrow( + `Unable to find network with chain id ${switchToChainId}`, + ); }); it('should not dispatch an alert when switchNetwork returns undefined', () => { diff --git a/app/core/DeeplinkManager/Handlers/switchNetwork.ts b/app/core/DeeplinkManager/Handlers/switchNetwork.ts index 27ad88e388c..2a63e3b684b 100644 --- a/app/core/DeeplinkManager/Handlers/switchNetwork.ts +++ b/app/core/DeeplinkManager/Handlers/switchNetwork.ts @@ -4,6 +4,10 @@ import { handleNetworkSwitch } from '../../../util/networks'; import DevLogger from '../../SDKConnect/utils/DevLogger'; import DeeplinkManager from '../DeeplinkManager'; +import { selectChainId } from '../../../selectors/networkController'; +import { store } from '../../../store'; +import { toHex } from '@metamask/controller-utils'; + function switchNetwork({ deeplinkManager, switchToChainId, @@ -15,11 +19,16 @@ function switchNetwork({ typeof switchToChainId === 'number' || typeof switchToChainId === 'string' ) { - const chainId = String(switchToChainId); - - const networkName = handleNetworkSwitch(chainId); + const newChainId = String(switchToChainId); + const networkName = handleNetworkSwitch(newChainId); - if (!networkName) return; + if (!networkName) { + const activeChainId = selectChainId(store.getState()); + if (activeChainId === toHex(newChainId)) { + return; + } + throw new Error(`Unable to find network with chain id ${newChainId}`); + } deeplinkManager.dispatch( showAlert({ From 0aae9b4ccff147f2fa441556dcc36927249eb380 Mon Sep 17 00:00:00 2001 From: Nick Gambino <35090461+gambinish@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:19:47 -0700 Subject: [PATCH 16/90] chore: Convert token sort `ActionSheet` to `BottomSheet` (#11853) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Converts the `ActionSheet` that controls [token sorting in this PR](https://github.com/MetaMask/metamask-mobile/pull/11618) to a `BottomSheet` per design spec. Design spec: https://www.figma.com/design/aMYisczaJyEsYl1TYdcPUL/Portfolio-View?node-id=5008-57060&node-type=frame&t=DkOQgh3ZMZfzy6C4-0 ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MMASSETS-432 ## **Manual testing steps** Functionality should remain the same as https://github.com/MetaMask/metamask-mobile/pull/11618 however rather than `ActionSheet` controls, we should have `BottomSheet` controls ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/00b1b471-996b-4a12-acfd-3f7c486bdbc8 https://github.com/user-attachments/assets/6160e434-dbbd-4b73-9edf-a971eea14448 ### **After** [](https://github.com/user-attachments/assets/752941e1-1ba6-4e23-ad26-ded482fb6c12) https://github.com/user-attachments/assets/bff36815-9ae4-4c02-a6a0-2e427365cddb ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: salimtb --- app/components/Nav/App/index.js | 5 + app/components/UI/Tokens/TokenList/index.tsx | 2 + .../TokenSortBottomSheet.test.tsx | 131 ++++++++++++++++++ .../TokenSortBottomSheet.tsx | 104 ++++++++++++++ .../UI/Tokens/TokensBottomSheet/index.ts | 8 ++ .../Tokens/__snapshots__/index.test.tsx.snap | 3 + app/components/UI/Tokens/index.test.tsx | 75 +++++++++- app/components/UI/Tokens/index.tsx | 40 +----- app/components/UI/Tokens/styles.ts | 11 ++ app/constants/navigation/Routes.ts | 1 + e2e/selectors/wallet/WalletView.selectors.js | 4 + 11 files changed, 346 insertions(+), 38 deletions(-) create mode 100644 app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.test.tsx create mode 100644 app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.tsx create mode 100644 app/components/UI/Tokens/TokensBottomSheet/index.ts diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 82d6268f1ed..1b79af4b2b7 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -58,6 +58,7 @@ import Toast, { ToastContext, } from '../../../component-library/components/Toast'; import AccountSelector from '../../../components/Views/AccountSelector'; +import TokenSortBottomSheet from '../../../components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.tsx'; import AccountConnect from '../../../components/Views/AccountConnect'; import AccountPermissions from '../../../components/Views/AccountPermissions'; import { AccountPermissionsScreens } from '../../../components/Views/AccountPermissions/AccountPermissions.types'; @@ -426,6 +427,10 @@ const RootModalFlow = () => ( name={Routes.SHEET.NETWORK_SELECTOR} component={NetworkSelector} /> + ( ({ + useSelector: jest.fn(), +})); + +jest.mock('../../../../util/theme', () => ({ + useTheme: jest.fn(), +})); + +jest.mock('../../../../core/Engine', () => ({ + context: { + PreferencesController: { + setTokenSortConfig: jest.fn(), + }, + }, +})); + +jest.mock('@react-navigation/native', () => { + const reactNavigationModule = jest.requireActual('@react-navigation/native'); + return { + ...reactNavigationModule, + useNavigation: () => ({ + navigate: jest.fn(), + goBack: jest.fn(), + }), + }; +}); + +jest.mock('react-native-safe-area-context', () => { + // copied from BottomSheetDialog.test.tsx + const inset = { top: 1, right: 2, bottom: 3, left: 4 }; + const frame = { width: 5, height: 6, x: 7, y: 8 }; + return { + SafeAreaProvider: jest.fn().mockImplementation(({ children }) => children), + SafeAreaConsumer: jest + .fn() + .mockImplementation(({ children }) => children(inset)), + useSafeAreaInsets: jest.fn().mockImplementation(() => inset), + useSafeAreaFrame: jest.fn().mockImplementation(() => frame), + }; +}); + +describe('TokenSortBottomSheet', () => { + beforeEach(() => { + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === selectTokenSortConfig) { + return { + key: 'tokenFiatAmount', + order: 'dsc', + sortCallback: 'stringNumeric', + }; // Default token sort config + } else if (selector === selectCurrentCurrency) { + return 'USD'; + } + return null; + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders correctly with the default sort option selected', () => { + const { queryByTestId } = render(); + + expect(queryByTestId(WalletViewSelectorsIDs.SORT_BY)).toBeTruthy(); + expect( + queryByTestId(WalletViewSelectorsIDs.SORT_DECLINING_BALANCE), + ).toBeTruthy(); + expect( + queryByTestId(WalletViewSelectorsIDs.SORT_ALPHABETICAL), + ).toBeTruthy(); + }); + + it('triggers PreferencesController to sort by token fiat amount when first cell is pressed', async () => { + const { queryByTestId } = render(); + + fireEvent.press( + queryByTestId(WalletViewSelectorsIDs.SORT_DECLINING_BALANCE), + ); + + await waitFor(() => { + expect( + Engine.context.PreferencesController.setTokenSortConfig, + ).toHaveBeenCalledWith({ + key: 'tokenFiatAmount', + order: 'dsc', + sortCallback: 'stringNumeric', + }); + }); + }); + + it('triggers PreferencesController to sort alphabetically when the second cell is pressed', async () => { + const { queryByTestId } = render(); + + fireEvent.press(queryByTestId(WalletViewSelectorsIDs.SORT_ALPHABETICAL)); + + await waitFor(() => { + expect( + Engine.context.PreferencesController.setTokenSortConfig, + ).toHaveBeenCalledWith({ + key: 'symbol', + sortCallback: 'alphaNumeric', + order: 'asc', + }); + }); + }); + + it('displays the correct selection based on tokenSortConfig', () => { + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === selectTokenSortConfig) { + return { key: 'symbol', order: 'dsc', sortCallback: 'stringNumeric' }; + } + return null; + }); + + const { queryByTestId } = render(); + + expect( + queryByTestId(WalletViewSelectorsIDs.SORT_ALPHABETICAL), + ).toBeTruthy(); + }); +}); diff --git a/app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.tsx b/app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.tsx new file mode 100644 index 00000000000..bdee8f734d3 --- /dev/null +++ b/app/components/UI/Tokens/TokensBottomSheet/TokenSortBottomSheet.tsx @@ -0,0 +1,104 @@ +import React, { useRef } from 'react'; +import { View } from 'react-native'; +import { useSelector } from 'react-redux'; +import { useTheme } from '../../../../util/theme'; +import Engine from '../../../../core/Engine'; +import createStyles from '../styles'; +import { strings } from '../../../../../locales/i18n'; +import { selectTokenSortConfig } from '../../../../selectors/preferencesController'; +import { selectCurrentCurrency } from '../../../../selectors/currencyRateController'; +import BottomSheet, { + BottomSheetRef, +} from '../../../../component-library/components/BottomSheets/BottomSheet'; +import Text, { + TextVariant, +} from '../../../../component-library/components/Texts/Text'; +import currencySymbols from '../../../../util/currency-symbols.json'; +import { WalletViewSelectorsIDs } from '../../../../../e2e/selectors/wallet/WalletView.selectors'; +import ListItemSelect from '../../../../component-library/components/List/ListItemSelect'; +import { VerticalAlignment } from '../../../../component-library/components/List/ListItem'; + +enum SortOption { + FiatAmount = 0, + Alphabetical = 1, +} + +const TokenSortBottomSheet = () => { + const sheetRef = useRef(null); + const { colors } = useTheme(); + const styles = createStyles(colors); + + const tokenSortConfig = useSelector(selectTokenSortConfig); + const currentCurrency = useSelector(selectCurrentCurrency); + + const onSortControlsBottomSheetPress = (option: SortOption) => { + const { PreferencesController } = Engine.context; + switch (option) { + case SortOption.FiatAmount: + PreferencesController.setTokenSortConfig({ + key: 'tokenFiatAmount', + order: 'dsc', + sortCallback: 'stringNumeric', + }); + sheetRef.current?.onCloseBottomSheet(); + break; + case SortOption.Alphabetical: + PreferencesController.setTokenSortConfig({ + key: 'symbol', + sortCallback: 'alphaNumeric', + order: 'asc', + }); + sheetRef.current?.onCloseBottomSheet(); + break; + default: + break; + } + }; + + return ( + + + + {strings('wallet.sort_by')} + + onSortControlsBottomSheetPress(SortOption.FiatAmount)} + isSelected={tokenSortConfig.key === 'tokenFiatAmount'} + isDisabled={false} + gap={8} + verticalAlignment={VerticalAlignment.Center} + > + + {strings('wallet.declining_balance', { + currency: + currencySymbols[ + currentCurrency as keyof typeof currencySymbols + ] ?? currentCurrency, + })} + + + + onSortControlsBottomSheetPress(SortOption.Alphabetical) + } + isSelected={tokenSortConfig.key !== 'tokenFiatAmount'} + isDisabled={false} + gap={8} + verticalAlignment={VerticalAlignment.Center} + > + + {strings('wallet.alphabetically')} + + + + + ); +}; + +export default TokenSortBottomSheet; diff --git a/app/components/UI/Tokens/TokensBottomSheet/index.ts b/app/components/UI/Tokens/TokensBottomSheet/index.ts new file mode 100644 index 00000000000..0f9bc12f503 --- /dev/null +++ b/app/components/UI/Tokens/TokensBottomSheet/index.ts @@ -0,0 +1,8 @@ +import Routes from '../../../../constants/navigation/Routes'; +import { createNavigationDetails } from '../../../../util/navigation/navUtils'; + +export const createTokensBottomSheetNavDetails = createNavigationDetails( + Routes.MODAL.ROOT_MODAL_FLOW, + Routes.SHEET.TOKEN_SORT, +); +export { default } from './TokenSortBottomSheet'; diff --git a/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap b/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap index 105de0a20a5..05f8d2ad9b5 100644 --- a/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/Tokens/__snapshots__/index.test.tsx.snap @@ -505,6 +505,7 @@ exports[`Tokens should hide zero balance tokens when setting is on 1`] = ` renderItem={[Function]} scrollEventThrottle={50} stickyHeaderIndices={[]} + testID="token-list" viewabilityConfigCallbackPairs={[]} > @@ -1746,6 +1747,7 @@ exports[`Tokens should render correctly 1`] = ` renderItem={[Function]} scrollEventThrottle={50} stickyHeaderIndices={[]} + testID="token-list" viewabilityConfigCallbackPairs={[]} > @@ -3005,6 +3007,7 @@ exports[`Tokens should show all balance tokens when hideZeroBalanceTokens settin renderItem={[Function]} scrollEventThrottle={50} stickyHeaderIndices={[]} + testID="token-list" viewabilityConfigCallbackPairs={[]} > diff --git a/app/components/UI/Tokens/index.test.tsx b/app/components/UI/Tokens/index.test.tsx index cee5b129426..60b1fb20ece 100644 --- a/app/components/UI/Tokens/index.test.tsx +++ b/app/components/UI/Tokens/index.test.tsx @@ -11,12 +11,35 @@ import { strings } from '../../../../locales/i18n'; import AppConstants from '../../../../app/core/AppConstants'; import Routes from '../../../../app/constants/navigation/Routes'; import { WalletViewSelectorsIDs } from '../../../../e2e/selectors/wallet/WalletView.selectors'; +import Engine from '../../../core/Engine'; +import { createTokensBottomSheetNavDetails } from './TokensBottomSheet'; + +jest.mock('../../../core/NotificationManager', () => ({ + showSimpleNotification: jest.fn(() => Promise.resolve()), +})); + +jest.mock('./TokensBottomSheet', () => ({ + createTokensBottomSheetNavDetails: jest.fn(() => ['BottomSheetScreen', {}]), +})); jest.mock('../../../core/Engine', () => ({ getTotalFiatAccountBalance: jest.fn(), context: { TokensController: { ignoreTokens: jest.fn(() => Promise.resolve()), + detectTokens: jest.fn(() => Promise.resolve()), + }, + TokenDetectionController: { + detectTokens: jest.fn(() => Promise.resolve()), + }, + AccountTrackerController: { + refresh: jest.fn(() => Promise.resolve()), + }, + CurrencyRateController: { + startPollingByNetworkClientId: jest.fn(() => Promise.resolve()), + }, + TokenRatesController: { + updateExchangeRates: jest.fn(() => Promise.resolve()), }, NetworkController: { getNetworkClientById: () => ({ @@ -153,6 +176,7 @@ describe('Tokens', () => { mockNavigate.mockClear(); mockPush.mockClear(); }); + it('should render correctly', () => { const { toJSON } = renderComponent(initialState); expect(toJSON()).toMatchSnapshot(); @@ -160,7 +184,6 @@ describe('Tokens', () => { it('should hide zero balance tokens when setting is on', async () => { const { toJSON, getByText, queryByText } = renderComponent(initialState); - // ETH and BAT should display expect(getByText('Ethereum')).toBeDefined(); await waitFor(() => expect(getByText('Bat')).toBeDefined()); @@ -180,7 +203,6 @@ describe('Tokens', () => { expect(getByText('Ethereum')).toBeDefined(); await waitFor(() => expect(getByText('Bat')).toBeDefined()); expect(getByText('Link')).toBeDefined(); - // All three should display expect(toJSON()).toMatchSnapshot(); }); @@ -252,6 +274,7 @@ describe('Tokens', () => { await findByText(strings('wallet.unable_to_find_conversion_rate')), ).toBeDefined(); }); + it('renders stake button correctly', () => { const { getByTestId } = renderComponent(initialState); @@ -272,4 +295,52 @@ describe('Tokens', () => { }); }); }); + + it('should refresh tokens and call necessary controllers', async () => { + const { getByTestId } = renderComponent(initialState); + + fireEvent.scroll( + getByTestId(WalletViewSelectorsIDs.TOKENS_CONTAINER_LIST), + { + nativeEvent: { + contentOffset: { y: 100 }, // Simulate scroll offset + contentSize: { height: 1000, width: 500 }, // Total size of scrollable content + layoutMeasurement: { height: 800, width: 500 }, // Size of the visible content area + }, + }, + ); + + fireEvent( + getByTestId(WalletViewSelectorsIDs.TOKENS_CONTAINER_LIST), + 'refresh', + { + refreshing: true, + }, + ); + + await waitFor(() => { + expect( + Engine.context.TokenDetectionController.detectTokens, + ).toHaveBeenCalled(); + expect( + Engine.context.AccountTrackerController.refresh, + ).toHaveBeenCalled(); + expect( + Engine.context.CurrencyRateController.startPollingByNetworkClientId, + ).toHaveBeenCalled(); + expect( + Engine.context.TokenRatesController.updateExchangeRates, + ).toHaveBeenCalled(); + }); + }); + + it('triggers bottom sheet when sort controls are pressed', async () => { + const { getByText } = renderComponent(initialState); + + await fireEvent.press(getByText('Sort by')); + + await waitFor(() => { + expect(createTokensBottomSheetNavDetails).toHaveBeenCalledWith({}); + }); + }); }); diff --git a/app/components/UI/Tokens/index.tsx b/app/components/UI/Tokens/index.tsx index 2747fee3b1c..c4604ac79ce 100644 --- a/app/components/UI/Tokens/index.tsx +++ b/app/components/UI/Tokens/index.tsx @@ -31,6 +31,7 @@ import { selectConversionRate, selectCurrentCurrency, } from '../../../selectors/currencyRateController'; +import { createTokensBottomSheetNavDetails } from './TokensBottomSheet'; import ButtonBase from '../../../component-library/components/Buttons/Button/foundation/ButtonBase'; // this will be imported from TokenRatesController when it is exported from there @@ -84,7 +85,6 @@ const Tokens: React.FC = ({ tokens }) => { const conversionRate = useSelector(selectConversionRate); const actionSheet = useRef(); - const sortControlsActionSheet = useRef(); const [tokenToRemove, setTokenToRemove] = useState(); const [refreshing, setRefreshing] = useState(false); const [isAddTokenEnabled, setIsAddTokenEnabled] = useState(true); @@ -142,7 +142,9 @@ const Tokens: React.FC = ({ tokens }) => { } }; - const showSortControls = () => sortControlsActionSheet?.current?.show(); + const showSortControls = () => { + navigation.navigate(...createTokensBottomSheetNavDetails({})); + }; const onRefresh = async () => { requestAnimationFrame(async () => { @@ -214,28 +216,6 @@ const Tokens: React.FC = ({ tokens }) => { const onActionSheetPress = (index: number) => index === 0 ? removeToken() : null; - const onSortControlsActionSheetPress = (index: number) => { - const { PreferencesController } = Engine.context; - switch (index) { - case 0: - PreferencesController.setTokenSortConfig({ - key: 'tokenFiatAmount', - order: 'dsc', - sortCallback: 'stringNumeric', - }); - break; - case 1: - PreferencesController.setTokenSortConfig({ - key: 'symbol', - sortCallback: 'alphaNumeric', - order: 'asc', - }); - break; - default: - break; - } - }; - return ( = ({ tokens }) => { style={styles.controlButton} /> - {tokensList && ( = ({ tokens }) => { destructiveButtonIndex={0} onPress={onActionSheetPress} /> - } - title={strings('wallet.sort_by')} - options={[ - strings('wallet.declining_balance', { currency: currentCurrency }), - strings('wallet.alphabetically'), - 'Cancel', - ]} - cancelButtonIndex={2} - onPress={onSortControlsActionSheetPress} - /> ); }; diff --git a/app/components/UI/Tokens/styles.ts b/app/components/UI/Tokens/styles.ts index 438ab229741..c5e907b102d 100644 --- a/app/components/UI/Tokens/styles.ts +++ b/app/components/UI/Tokens/styles.ts @@ -9,6 +9,17 @@ const createStyles = (colors: Colors) => backgroundColor: colors.background.default, flex: 1, }, + bottomSheetWrapper: { + alignItems: 'flex-start', + }, + bottomSheetTitle: { + alignSelf: 'center', + paddingTop: 16, + paddingBottom: 16, + }, + bottomSheetText: { + width: '100%', + }, emptyView: { backgroundColor: colors.background.default, justifyContent: 'center', diff --git a/app/constants/navigation/Routes.ts b/app/constants/navigation/Routes.ts index 1d95bc387f7..cf7bcc7d9f0 100644 --- a/app/constants/navigation/Routes.ts +++ b/app/constants/navigation/Routes.ts @@ -112,6 +112,7 @@ const Routes = { SHOW_TOKEN_ID: 'ShowTokenId', ORIGIN_SPAM_MODAL: 'OriginSpamModal', TOOLTIP_MODAL: 'tooltipModal', + TOKEN_SORT: 'TokenSort', }, BROWSER: { HOME: 'BrowserTabHome', diff --git a/e2e/selectors/wallet/WalletView.selectors.js b/e2e/selectors/wallet/WalletView.selectors.js index e64f1f2c056..265a13cd0b1 100644 --- a/e2e/selectors/wallet/WalletView.selectors.js +++ b/e2e/selectors/wallet/WalletView.selectors.js @@ -19,6 +19,7 @@ export const WalletViewSelectorsIDs = { ACCOUNT_NAME_LABEL_INPUT: 'account-label-text-input', ACCOUNT_NAME_LABEL_TEXT: 'account-label', TOKENS_CONTAINER: 'tokens', + TOKENS_CONTAINER_LIST: 'token-list', ACCOUNT_OVERVIEW: 'account-overview', ACCOUNT_ACTIONS: 'main-wallet-account-actions', ACCOUNT_COPY_BUTTON: 'wallet-account-copy-button', @@ -26,6 +27,9 @@ export const WalletViewSelectorsIDs = { TEST_COLLECTIBLE: 'collectible-Test Dapp NFTs #1-1', COLLECTIBLE_FALLBACK: 'fallback-nft-with-token-id', IMPORT_TOKEN_FOOTER_LINK: 'import-token-footer-link', + SORT_DECLINING_BALANCE: 'sort-declining-balance', + SORT_ALPHABETICAL: 'sort-alphabetical', + SORT_BY: 'sort-by', }; export const WalletViewSelectorsText = { From 1f5f852e08b531ef79faee1a0027000bbdd62944 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:00:34 +0000 Subject: [PATCH 17/90] chore(devDeps): detox@20.27.2->^20.27.5 (#12039) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - bump `detox` - migrate detox patch Silence `patch-package` setup warning ## **Related issues** ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- package.json | 2 +- ...detox+20.23.1.patch => detox+20.27.5.patch} | 0 yarn.lock | 18 +++++++++--------- 3 files changed, 10 insertions(+), 10 deletions(-) rename patches/{detox+20.23.1.patch => detox+20.27.5.patch} (100%) diff --git a/package.json b/package.json index 49309856adf..0682450f541 100644 --- a/package.json +++ b/package.json @@ -434,7 +434,7 @@ "browserstack-local": "^1.5.1", "chromedriver": "^123.0.1", "depcheck": "^1.4.7", - "detox": "20.27.2", + "detox": "^20.27.5", "dotenv": "^16.0.3", "enzyme": "3.9.0", "enzyme-adapter-react-16": "1.10.0", diff --git a/patches/detox+20.23.1.patch b/patches/detox+20.27.5.patch similarity index 100% rename from patches/detox+20.23.1.patch rename to patches/detox+20.27.5.patch diff --git a/yarn.lock b/yarn.lock index 0de7e3f473c..edc0f9c3ca0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15676,15 +15676,15 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -detox-copilot@^0.0.9: - version "0.0.9" - resolved "https://registry.yarnpkg.com/detox-copilot/-/detox-copilot-0.0.9.tgz#cc1ddd869868987d3527c93d2604b5d66f3c8466" - integrity sha512-Wk2fuisD8EH+349b0ysNWvZ7UEsThAChbYFlLqOR1jWkDaonEvgf6IOUlmxjvyTl9ENtl8ckd1U7k94yCBYwqw== +detox-copilot@^0.0.23: + version "0.0.23" + resolved "https://registry.yarnpkg.com/detox-copilot/-/detox-copilot-0.0.23.tgz#724aeb62424018b4b6d5620bb0dc7e800e4e4f6b" + integrity sha512-qDSdLwgPUMVawpE0R3agNWd2U69ilTnhf+SodSqqrkmTI0oG67IfkACvwox+K9Slcc8ki6y0Bw6QVBi54MqpaA== -detox@20.27.2: - version "20.27.2" - resolved "https://registry.yarnpkg.com/detox/-/detox-20.27.2.tgz#aa22a146b968b6e5f78687557081cf32d26ca066" - integrity sha512-cC6S40v7ix+uA5jYzG8eazSs7YtOWgc2aCwWLZIIzfE5Kvo0gfHgtqeRhrYWCMZaj/irKKs39h2B070oNQOIrA== +detox@^20.27.5: + version "20.27.5" + resolved "https://registry.yarnpkg.com/detox/-/detox-20.27.5.tgz#f67d1a0c9ddbb2b6edb838e1b32c63b486be66ea" + integrity sha512-JBe3fONwaSxYubd/36SZh3c2MaYs+Cx7sOA4GJfh16QTyoB7XvvbGrSlQDTbag/f0j5RZt4judPtg5A3P1/Uhg== dependencies: ajv "^8.6.3" bunyan "^1.8.12" @@ -15692,7 +15692,7 @@ detox@20.27.2: caf "^15.0.1" chalk "^4.0.0" child-process-promise "^2.2.0" - detox-copilot "^0.0.9" + detox-copilot "^0.0.23" execa "^5.1.1" find-up "^5.0.0" fs-extra "^11.0.0" From fe4ad1e7791dee97aeee0130d54ba8f671d7ce2a Mon Sep 17 00:00:00 2001 From: Brendan Kirby <124314512+bkirb@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:07:20 -0700 Subject: [PATCH 18/90] test: skip onramp onboarding for returning user (#11591) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This tests that a returning user in the buy flow _does not_ see the onboarding flow again, or the steps to select region and payment method. It should skip to the build quote screen. ## **Related issues** https://consensyssoftware.atlassian.net/browse/RAMPS-1871 ## **Manual testing steps** All Onramp tests are passing ``` PASS e2e/specs/ramps/onramp.spec.js (52.479 s) smokeAssets Buy Crypto ✓ should select Region and Payment Method to see the Build Quote screen (16291 ms) ✓ should skip to the Build Quote screen for returning user (14077 ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 52.55 s, estimated 55 s ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- e2e/pages/Ramps/BuildQuoteView.js | 9 +++++++++ e2e/selectors/Ramps/BuildQuote.selectors.js | 1 + e2e/specs/ramps/onramp.spec.js | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/e2e/pages/Ramps/BuildQuoteView.js b/e2e/pages/Ramps/BuildQuoteView.js index 63c916c0833..407abb8177d 100644 --- a/e2e/pages/Ramps/BuildQuoteView.js +++ b/e2e/pages/Ramps/BuildQuoteView.js @@ -1,4 +1,5 @@ import Matchers from '../../utils/Matchers'; +import Gestures from '../../utils/Gestures'; import { BuildQuoteSelectors } from '../../selectors/Ramps/BuildQuote.selectors'; class BuildQuoteView { @@ -13,6 +14,14 @@ class BuildQuoteView { get getQuotesButton() { return Matchers.getElementByText(BuildQuoteSelectors.GET_QUOTES_BUTTON); } + + get cancelButton() { + return Matchers.getElementByText(BuildQuoteSelectors.CANCEL_BUTTON_TEXT); + } + + async tapCancelButton() { + await Gestures.waitAndTap(this.cancelButton); + } } export default new BuildQuoteView(); diff --git a/e2e/selectors/Ramps/BuildQuote.selectors.js b/e2e/selectors/Ramps/BuildQuote.selectors.js index 1c3a116b9f8..e8eaf68ca4f 100644 --- a/e2e/selectors/Ramps/BuildQuote.selectors.js +++ b/e2e/selectors/Ramps/BuildQuote.selectors.js @@ -4,4 +4,5 @@ export const BuildQuoteSelectors = { AMOUNT_TO_BUY_LABEL: enContent.fiat_on_ramp_aggregator.amount_to_buy, AMOUNT_TO_SELL_LABEL: enContent.fiat_on_ramp_aggregator.amount_to_sell, GET_QUOTES_BUTTON: enContent.fiat_on_ramp_aggregator.get_quotes, + CANCEL_BUTTON_TEXT: enContent.navigation.cancel, }; diff --git a/e2e/specs/ramps/onramp.spec.js b/e2e/specs/ramps/onramp.spec.js index e426e34e828..54b8e4fe7a7 100644 --- a/e2e/specs/ramps/onramp.spec.js +++ b/e2e/specs/ramps/onramp.spec.js @@ -54,5 +54,13 @@ describe(SmokeAssets('Buy Crypto'), () => { await SelectPaymentMethodView.tapContinueButton(); await Assertions.checkIfVisible(BuildQuoteView.amountToBuyLabel); await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); + await BuildQuoteView.tapCancelButton(); + }); + + it('should skip to the Build Quote screen for returning user', async () => { + await TabBarComponent.tapActions(); + await WalletActionsModal.tapBuyButton(); + await Assertions.checkIfVisible(BuildQuoteView.amountToBuyLabel); + await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); }); }); From 20bf1b77abc2671ccd0cb5836cf0bba6ef5415e7 Mon Sep 17 00:00:00 2001 From: Curtis David Date: Mon, 28 Oct 2024 20:14:48 -0400 Subject: [PATCH 19/90] test: change ramps e2e tag (#12062) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR temporarily moves the recently added ramps tests to the core tag. https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/1fdea2be-653b-4198-bd94-99e87be59d9e?tab=workflows ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- e2e/specs/ramps/offramp.spec.js | 13 +++++++------ e2e/specs/ramps/onramp.spec.js | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/e2e/specs/ramps/offramp.spec.js b/e2e/specs/ramps/offramp.spec.js index d990ed0993b..38355b9719f 100644 --- a/e2e/specs/ramps/offramp.spec.js +++ b/e2e/specs/ramps/offramp.spec.js @@ -12,7 +12,7 @@ import { CustomNetworks } from '../../resources/networks.e2e'; import TestHelpers from '../../helpers'; import FixtureServer from '../../fixtures/fixture-server'; import { getFixturesServerPort } from '../../fixtures/utils'; -import { SmokeAssets } from '../../tags'; +import { SmokeCore } from '../../tags'; import Assertions from '../../utils/Assertions'; import SellGetStartedView from '../../pages/Ramps/SellGetStartedView'; import SelectRegionView from '../../pages/Ramps/SelectRegionView'; @@ -32,9 +32,9 @@ const PaymentMethods = { DEBIT_OR_CREDIT: 'Debit or Credit', INSTANT_ACH_BANK_TRANSFER: 'Insant ACH Bank Transfer', ACH_BANK_TRANSFER: 'ACH Bank Transfer', -} +}; -describe(SmokeAssets('Off-Ramp'), () => { +describe(SmokeCore('Off-Ramp'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder() @@ -66,10 +66,11 @@ describe(SmokeAssets('Off-Ramp'), () => { await SelectRegionView.tapRegionOption(Regions.USA); await SelectRegionView.tapRegionOption(Regions.CALIFORNIA); await SelectRegionView.tapContinueButton(); - await SelectPaymentMethodView.tapPaymentMethodOption(PaymentMethods.DEBIT_OR_CREDIT); - await SelectPaymentMethodView.tapContinueButton(); + await SelectPaymentMethodView.tapPaymentMethodOption( + PaymentMethods.DEBIT_OR_CREDIT, + ); + await SelectPaymentMethodView.tapContinueButton(); await Assertions.checkIfVisible(BuildQuoteView.amountToSellLabel); await Assertions.checkIfVisible(BuildQuoteView.getQuotesButton); }); - }); diff --git a/e2e/specs/ramps/onramp.spec.js b/e2e/specs/ramps/onramp.spec.js index 54b8e4fe7a7..f6f205c82e0 100644 --- a/e2e/specs/ramps/onramp.spec.js +++ b/e2e/specs/ramps/onramp.spec.js @@ -11,7 +11,7 @@ import { import TestHelpers from '../../helpers'; import FixtureServer from '../../fixtures/fixture-server'; import { getFixturesServerPort } from '../../fixtures/utils'; -import { SmokeAssets } from '../../tags'; +import { SmokeCore } from '../../tags'; import BuyGetStartedView from '../../pages/Ramps/BuyGetStartedView'; import SelectRegionView from '../../pages/Ramps/SelectRegionView'; import SelectPaymentMethodView from '../../pages/Ramps/SelectPaymentMethodView'; @@ -20,7 +20,7 @@ import Assertions from '../../utils/Assertions'; const fixtureServer = new FixtureServer(); -describe(SmokeAssets('Buy Crypto'), () => { +describe(SmokeCore('Buy Crypto'), () => { beforeAll(async () => { await TestHelpers.reverseServerPort(); const fixture = new FixtureBuilder().build(); From 088a4266d82dc26cea006bb0b9b8c423196278a2 Mon Sep 17 00:00:00 2001 From: Salim TOUBAL Date: Tue, 29 Oct 2024 10:13:26 +0100 Subject: [PATCH 20/90] fix: fix assets detail page crash (#12064) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** After tapping a send token deeplink and cancelling the send on Confirm screen the token to send is added to wallet account and displayed on token list. Tokens that are auto-added by a deeplink will crash app on Token Details view, even if the Token was already imported before tapping deeplink. Send token deeplink: https://metamask.app.link/send/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48@1/transfer?address=0x2990079bcdEe240329a520d2444386FC119da21a&uint256=2.5e7 ## **Related issues** Fixes: #11984 ## **Manual testing steps** 1. Go to the wallet page 2. Click on the link on the description outside of the app 3. go to token details page ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../__snapshots__/index.test.tsx.snap | 40 +++++++++++++++++ .../Views/AssetDetails/index.test.tsx | 44 +++++++++++++++++++ app/components/Views/AssetDetails/index.tsx | 9 +--- 3 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 app/components/Views/AssetDetails/__snapshots__/index.test.tsx.snap create mode 100644 app/components/Views/AssetDetails/index.test.tsx diff --git a/app/components/Views/AssetDetails/__snapshots__/index.test.tsx.snap b/app/components/Views/AssetDetails/__snapshots__/index.test.tsx.snap new file mode 100644 index 00000000000..0c238dcc27e --- /dev/null +++ b/app/components/Views/AssetDetails/__snapshots__/index.test.tsx.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AssetsDetails should render correctly 1`] = ` + + + +`; diff --git a/app/components/Views/AssetDetails/index.test.tsx b/app/components/Views/AssetDetails/index.test.tsx new file mode 100644 index 00000000000..ac085b4f776 --- /dev/null +++ b/app/components/Views/AssetDetails/index.test.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import AssetDetails from './'; +import configureMockStore from 'redux-mock-store'; +import { shallow } from 'enzyme'; +import { Provider } from 'react-redux'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import { backgroundState } from '../../../util/test/initial-root-state'; +import { mockNetworkState } from '../../../util/test/network'; + +const mockStore = configureMockStore(); + +const initialState = { + engine: { + backgroundState: { + ...backgroundState, + NetworkController: { + ...mockNetworkState({ + chainId: CHAIN_IDS.MAINNET, + id: 'mainnet', + nickname: 'Ethereum Mainnet', + ticker: 'ETH', + }), + }, + }, + }, +}; +const store = mockStore(initialState); + +describe('AssetsDetails', () => { + it('should render correctly', () => { + const wrapper = shallow( + + + , + ); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/app/components/Views/AssetDetails/index.tsx b/app/components/Views/AssetDetails/index.tsx index 56d48e62bd2..bb97c33b30a 100644 --- a/app/components/Views/AssetDetails/index.tsx +++ b/app/components/Views/AssetDetails/index.tsx @@ -46,7 +46,6 @@ import { useMetrics } from '../../../components/hooks/useMetrics'; import { RootState } from 'app/reducers'; import { Colors } from '../../../util/theme/models'; import { Hex } from '@metamask/utils'; -import { RpcEndpointType } from '@metamask/network-controller'; const createStyles = (colors: Colors) => StyleSheet.create({ @@ -134,12 +133,8 @@ const AssetDetails = (props: Props) => { name = providerConfig.nickname; } else { name = - /* - * TODO: remove any as soon as NetworkController - * removes goerli from provider config types - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (Networks as any)[providerConfig?.type ?? RpcEndpointType.Custom]; + (Networks as Record)[providerConfig.type] + ?.name || { ...Networks.rpc, color: null }.name; } return name; }; From c773d7a29f4e7996e422507a2f987dfc87a0f2bd Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:32:29 +0000 Subject: [PATCH 21/90] chore: eth-json-rpc-filters@^6.0.1 -> @metamask/eth-json-rpc-filters@^8.0.0 (#12024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Replace deprecated `eth-json-rpc-filters` with `@metamask/eth-json-rpc-filters`. ## **Related issues** - Part of: #12047 - Broken out from: #9274, #11952 - Follow-up to: #11980 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/core/BackgroundBridge/BackgroundBridge.js | 4 +-- app/core/Snaps/SnapBridge.ts | 4 +-- package.json | 2 +- ...@metamask+post-message-stream+8.1.1.patch} | 4 +-- yarn.lock | 30 +++++++------------ 5 files changed, 18 insertions(+), 26 deletions(-) rename patches/{@metamask+post-message-stream+8.1.0.patch => @metamask+post-message-stream+8.1.1.patch} (95%) diff --git a/app/core/BackgroundBridge/BackgroundBridge.js b/app/core/BackgroundBridge/BackgroundBridge.js index 78dd22aa8b7..c20eb769412 100644 --- a/app/core/BackgroundBridge/BackgroundBridge.js +++ b/app/core/BackgroundBridge/BackgroundBridge.js @@ -26,8 +26,8 @@ import snapMethodMiddlewareBuilder from '../Snaps/SnapsMethodMiddleware'; import { SubjectType } from '@metamask/permission-controller'; ///: END:ONLY_INCLUDE_IF -const createFilterMiddleware = require('eth-json-rpc-filters'); -const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager'); +const createFilterMiddleware = require('@metamask/eth-json-rpc-filters'); +const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager'); const { providerAsMiddleware } = require('eth-json-rpc-middleware'); const pump = require('pump'); // eslint-disable-next-line import/no-nodejs-modules diff --git a/app/core/Snaps/SnapBridge.ts b/app/core/Snaps/SnapBridge.ts index 2ab13fbf5d0..ae26822fc71 100644 --- a/app/core/Snaps/SnapBridge.ts +++ b/app/core/Snaps/SnapBridge.ts @@ -22,8 +22,8 @@ import snapMethodMiddlewareBuilder from './SnapsMethodMiddleware'; import { SubjectType } from '@metamask/permission-controller'; const ObjectMultiplex = require('@metamask/object-multiplex'); -const createFilterMiddleware = require('eth-json-rpc-filters'); -const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager'); +const createFilterMiddleware = require('@metamask/eth-json-rpc-filters'); +const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager'); const { providerAsMiddleware } = require('eth-json-rpc-middleware'); const pump = require('pump'); diff --git a/package.json b/package.json index 0682450f541..374e22b1890 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,7 @@ "@metamask/contract-metadata": "^2.1.0", "@metamask/controller-utils": "^11.3.0", "@metamask/design-tokens": "^4.0.0", + "@metamask/eth-json-rpc-filters": "^8.0.0", "@metamask/eth-ledger-bridge-keyring": "^4.1.0", "@metamask/eth-query": "^4.0.0", "@metamask/eth-sig-util": "^7.0.2", @@ -239,7 +240,6 @@ "eciesjs": "^0.3.15", "eth-block-tracker": "^7.0.1", "eth-ens-namehash": "2.0.8", - "eth-json-rpc-filters": "^6.0.1", "eth-json-rpc-middleware": "9.0.1", "eth-url-parser": "1.0.4", "ethereumjs-abi": "0.6.6", diff --git a/patches/@metamask+post-message-stream+8.1.0.patch b/patches/@metamask+post-message-stream+8.1.1.patch similarity index 95% rename from patches/@metamask+post-message-stream+8.1.0.patch rename to patches/@metamask+post-message-stream+8.1.1.patch index 22d35a8aee5..1f320420ffb 100644 --- a/patches/@metamask+post-message-stream+8.1.0.patch +++ b/patches/@metamask+post-message-stream+8.1.1.patch @@ -1,8 +1,8 @@ diff --git a/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js b/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js -index cead325..a319ed7 100644 +index f2e42ef..27807bb 100644 --- a/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js +++ b/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js -@@ -6,11 +6,21 @@ const utils_1 = require("@metamask/utils"); +@@ -17,11 +17,21 @@ const utils_1 = require("@metamask/utils"); const BasePostMessageStream_1 = require("../BasePostMessageStream"); const utils_2 = require("../utils"); /* istanbul ignore next */ diff --git a/yarn.lock b/yarn.lock index edc0f9c3ca0..f467669969c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4529,6 +4529,17 @@ "@metamask/utils" "^9.2.1" ethereum-cryptography "^2.1.2" +"@metamask/eth-json-rpc-filters@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-filters/-/eth-json-rpc-filters-8.0.0.tgz#fd0ca224dc198e270e142c1f2007e05cacb5f16a" + integrity sha512-kDwSoas8gYWtN79AO4vvyKvaL8bIMstpuwZdsWTSc1goBFTOJEscCD6zUX+MOQFnQohFoC512mNeA5tPLRV46A== + dependencies: + "@metamask/eth-query" "^4.0.0" + "@metamask/json-rpc-engine" "^9.0.0" + "@metamask/safe-event-emitter" "^3.0.0" + async-mutex "^0.5.0" + pify "^5.0.0" + "@metamask/eth-json-rpc-infura@^9.0.0", "@metamask/eth-json-rpc-infura@^9.1.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-infura/-/eth-json-rpc-infura-9.1.0.tgz#8e09588ed58f49058615cab7040dcbce4682a292" @@ -16998,17 +17009,6 @@ eth-ens-namehash@^1.0.2: idna-uts46 "^1.0.1" js-sha3 "^0.5.7" -eth-json-rpc-filters@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz#0b3e370f017f5c6f58d3e7bd0756d8099ed85c56" - integrity sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig== - dependencies: - "@metamask/safe-event-emitter" "^3.0.0" - async-mutex "^0.2.6" - eth-query "^2.1.2" - json-rpc-engine "^6.1.0" - pify "^5.0.0" - eth-json-rpc-middleware@9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-9.0.1.tgz#193cb05174739fb736737bbbf992e13010c4b44e" @@ -17041,14 +17041,6 @@ eth-phishing-detect@^1.2.0: dependencies: fast-levenshtein "^2.0.6" -eth-query@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" - integrity sha1-1nQdkAAQa1FRDHLbktY2VFam2l4= - dependencies: - json-rpc-random-id "^1.0.0" - xtend "^4.0.1" - eth-rpc-errors@^4.0.2, eth-rpc-errors@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" From 0477b84135bc1058655de11ce06704034c8e8e4c Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:53:23 +0000 Subject: [PATCH 22/90] fix: google plist ios build issue (#12075) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR aims to fix the problem in building iOS variants while using Firebase. `Exception NSException * "Configuration fails. It may be caused by an invalid GOOGLE_APP_ID in GoogleService-Info.plist or set in the customized options." 0x0000600000c16250` ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- README.md | 13 ++++++++++--- ios/GoogleServices/GoogleService-Info-example.plist | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 587898dcbd4..815748fcafd 100644 --- a/README.md +++ b/README.md @@ -41,18 +41,25 @@ cd metamask-mobile **Firebase Messaging Setup** -Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` or `GoogleService-Info.plist` file in the `ios` directory. In case you don't have FCM account, you can use `./android/app/google-services-example.json` for Android or `./ios/GoogleServices/GoogleService-Info-example.plist` for iOS and follow the steps below to populate the correct environment variables in the `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` variable depending on the environment you are running the app (ios/android). +Before running the app, keep in mind that MetaMask uses FCM (Firebase Cloud Message) to empower communications. Based on this, as an external contributor you would preferably need to provide your own FREE Firebase project config file with a matching client for package name `io.metamask`, and update your `google-services.json` file in the `android/app` or `GoogleService-Info.plist` file in the `ios` directory. + +**External Contributors** +In case you don't have FCM account, you can use `./android/app/google-services-example.json` for Android or `./ios/GoogleServices/GoogleService-Info-example.plist` for iOS and follow the steps below to populate the correct environment variables in the `.env` files (`.ios.env`, `.js.env`, `.android.env`), adding `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` variable depending on the environment you are running the app (ios/android). + +**Internal Contributors** + +We should access the Firebase project config file from 1Password. The value you should provide to `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` is the base64 encoded version of your Firebase project config file, which can be generated as follows: **For Android** ```bash -echo "export GOOGLE_SERVICES_B64_ANDROID=\"$(base64 -w0 -i ./android/app/google-services-example.json)\"" | tee -a .js.env .ios.env .android.env +export GOOGLE_SERVICES_B64_ANDROID="$(base64 -w0 -i ./android/app/google-services-example.json)" && echo "export GOOGLE_SERVICES_B64_ANDROID=\"$GOOGLE_SERVICES_B64_ANDROID\"" | tee -a .js.env .ios.env ``` **For iOS** ```bash -echo "export GOOGLE_SERVICES_B64_IOS=\"$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info-example.plist)\"" | tee -a .js.env .ios.env +export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info-example.plist)" && echo "export GOOGLE_SERVICES_B64_IOS=\"$GOOGLE_SERVICES_B64_IOS\"" | tee -a .js.env .ios.env ``` [!CAUTION] diff --git a/ios/GoogleServices/GoogleService-Info-example.plist b/ios/GoogleServices/GoogleService-Info-example.plist index 1294630b17d..b9d5c5040ae 100644 --- a/ios/GoogleServices/GoogleService-Info-example.plist +++ b/ios/GoogleServices/GoogleService-Info-example.plist @@ -25,6 +25,6 @@ IS_SIGNIN_ENABLED GOOGLE_APP_ID - mock-google-app-id-1234 + 1:824598429541:ios:7b7482c4598025a5beab8c From 8ddfa32815ffa73bd9d3133e7febef16d188edd8 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:01:49 +0000 Subject: [PATCH 23/90] fix: eth-json-rpc-middleware@9 -> @metamask/eth-json-rpc-middleware@11 (#12047) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Migrate from legacy `eth-json-rpc-middleware` to `@metamask/eth-json-rpc-middleware`, holding at v11. Removes usage of `eth-block-tracker` v5. ## **Related issues** - Based on: #12024 - Follow-up to: #12008 - Broken out from: #11952 ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- app/core/BackgroundBridge/BackgroundBridge.js | 2 +- app/core/Snaps/SnapBridge.ts | 2 +- package.json | 2 +- yarn.lock | 97 ++++++++----------- 4 files changed, 42 insertions(+), 61 deletions(-) diff --git a/app/core/BackgroundBridge/BackgroundBridge.js b/app/core/BackgroundBridge/BackgroundBridge.js index c20eb769412..3af46b160d9 100644 --- a/app/core/BackgroundBridge/BackgroundBridge.js +++ b/app/core/BackgroundBridge/BackgroundBridge.js @@ -28,7 +28,7 @@ import { SubjectType } from '@metamask/permission-controller'; const createFilterMiddleware = require('@metamask/eth-json-rpc-filters'); const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager'); -const { providerAsMiddleware } = require('eth-json-rpc-middleware'); +const { providerAsMiddleware } = require('@metamask/eth-json-rpc-middleware'); const pump = require('pump'); // eslint-disable-next-line import/no-nodejs-modules const EventEmitter = require('events').EventEmitter; diff --git a/app/core/Snaps/SnapBridge.ts b/app/core/Snaps/SnapBridge.ts index ae26822fc71..47c067f155c 100644 --- a/app/core/Snaps/SnapBridge.ts +++ b/app/core/Snaps/SnapBridge.ts @@ -24,7 +24,7 @@ import { SubjectType } from '@metamask/permission-controller'; const ObjectMultiplex = require('@metamask/object-multiplex'); const createFilterMiddleware = require('@metamask/eth-json-rpc-filters'); const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager'); -const { providerAsMiddleware } = require('eth-json-rpc-middleware'); +const { providerAsMiddleware } = require('@metamask/eth-json-rpc-middleware'); const pump = require('pump'); interface ISnapBridgeProps { diff --git a/package.json b/package.json index 374e22b1890..f35e69939e9 100644 --- a/package.json +++ b/package.json @@ -149,6 +149,7 @@ "@metamask/controller-utils": "^11.3.0", "@metamask/design-tokens": "^4.0.0", "@metamask/eth-json-rpc-filters": "^8.0.0", + "@metamask/eth-json-rpc-middleware": "^11.0.2", "@metamask/eth-ledger-bridge-keyring": "^4.1.0", "@metamask/eth-query": "^4.0.0", "@metamask/eth-sig-util": "^7.0.2", @@ -240,7 +241,6 @@ "eciesjs": "^0.3.15", "eth-block-tracker": "^7.0.1", "eth-ens-namehash": "2.0.8", - "eth-json-rpc-middleware": "9.0.1", "eth-url-parser": "1.0.4", "ethereumjs-abi": "0.6.6", "ethereumjs-util": "6.1.0", diff --git a/yarn.lock b/yarn.lock index f467669969c..a7730cef374 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1859,7 +1859,7 @@ "@ethereumjs/util" "^9.0.3" ethereum-cryptography "^2.1.3" -"@ethereumjs/util@^8.0.0", "@ethereumjs/util@^8.0.6", "@ethereumjs/util@^8.1.0": +"@ethereumjs/util@^8.0.0", "@ethereumjs/util@^8.1.0": version "8.1.0" resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== @@ -4286,6 +4286,14 @@ resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.8.0.tgz#fc32e07746689459c4b049dc581d1dbda5545686" integrity sha512-+70fkgjhVJeJ+nJqnburIM3UAsfvxat1Low9HMPobLbv64FIdB4Nzu5ct3qojNQ58r5sK01tg5UoFIJYslaVrg== +"@metamask/abi-utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-1.2.0.tgz#068e1b0f5e423dfae96961e0e5276a7c1babc03a" + integrity sha512-Hf7fnBDM9ptCPDtq/wQffWbw859CdVGMwlpWUEsTH6gLXhXONGrRXHA2piyYPRuia8YYTdJvRC/zSK1/nyLvYg== + dependencies: + "@metamask/utils" "^3.4.1" + superstruct "^1.0.3" + "@metamask/abi-utils@^2.0.2", "@metamask/abi-utils@^2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@metamask/abi-utils/-/abi-utils-2.0.4.tgz#20908c1d910f7a17a89fdf5778a5c59d5cb8b8be" @@ -4551,6 +4559,21 @@ "@metamask/utils" "^8.1.0" node-fetch "^2.7.0" +"@metamask/eth-json-rpc-middleware@^11.0.2": + version "11.0.2" + resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-middleware/-/eth-json-rpc-middleware-11.0.2.tgz#85e6639f5d159a3277d13609dea9f12ebfb5b4e8" + integrity sha512-/HqtuK/6E8sIJmzg0O3Ey5JsgK6O/VbDqg5R9thHFQMi9EtKXnnZFc8Blir7IOQraGVJFiZQIKZMHRTNQRyreg== + dependencies: + "@metamask/eth-json-rpc-provider" "^1.0.0" + "@metamask/eth-sig-util" "^6.0.0" + "@metamask/utils" "^5.0.1" + clone "^2.1.1" + eth-block-tracker "^7.0.1" + eth-rpc-errors "^4.0.3" + json-rpc-engine "^6.1.0" + pify "^3.0.0" + safe-stable-stringify "^2.3.2" + "@metamask/eth-json-rpc-middleware@^12.1.0", "@metamask/eth-json-rpc-middleware@^12.1.1": version "12.1.1" resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-middleware/-/eth-json-rpc-middleware-12.1.1.tgz#5b6a19386f420211cb554c637f0927b76dc3167a" @@ -4641,14 +4664,15 @@ json-rpc-random-id "^1.0.0" xtend "^4.0.1" -"@metamask/eth-sig-util@^5.0.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-5.1.0.tgz#a47f62800ee1917fef976ba67544a0ccd7d1bd6b" - integrity sha512-mlgziIHYlA9pi/XZerChqg4NocdOgBPB9NmxgXWQO2U2hH8RGOJQrz6j/AIKkYxgCMIE2PY000+joOwXfzeTDQ== +"@metamask/eth-sig-util@^6.0.0": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-6.0.2.tgz#d81dc87e0cd5a6580010911501976b48821746ad" + integrity sha512-D6IIefM2vS+4GUGGtezdBbkwUYQC4bCosYx/JteUuF0zfe6lyxR4cruA8+2QHoUg7F7edNH1xymYpqYq1BeOkw== dependencies: - "@ethereumjs/util" "^8.0.6" - bn.js "^4.12.0" - ethereum-cryptography "^2.0.0" + "@ethereumjs/util" "^8.1.0" + "@metamask/abi-utils" "^1.2.0" + "@metamask/utils" "^5.0.2" + ethereum-cryptography "^2.1.2" ethjs-util "^0.1.6" tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" @@ -5673,7 +5697,7 @@ lodash "^4.17.21" uuid "^8.3.2" -"@metamask/utils@^3.0.3": +"@metamask/utils@^3.4.1": version "3.6.0" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-3.6.0.tgz#b218b969a05ca7a8093b5d1670f6625061de707d" integrity sha512-9cIRrfkWvHblSiNDVXsjivqa9Ak0RYo/1H6tqTqTbAx+oBK2Sva0lWDHxGchOqA7bySGUJKAWSNJvH6gdHZ0gQ== @@ -5683,7 +5707,7 @@ semver "^7.3.8" superstruct "^1.0.3" -"@metamask/utils@^5.0.1": +"@metamask/utils@^5.0.1", "@metamask/utils@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-5.0.2.tgz#140ba5061d90d9dac0280c19cab101bc18c8857c" integrity sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g== @@ -13389,7 +13413,7 @@ bn.js@5.2.1, bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -13599,11 +13623,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" - integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== - buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -16962,15 +16981,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eth-block-tracker@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-5.0.1.tgz#c5ad39902bd0454223b601ec0874f9fcc9f30eed" - integrity sha512-NVs+JDSux0FdmOrl3A2YDcQFkkYf9/qW9irvPmtC7bhMoPAe6oBlaqqe/m9Ixh5rkKqAox4mEyWGpsFmf/IsNw== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - json-rpc-random-id "^1.0.1" - pify "^3.0.0" - eth-block-tracker@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz#dfc16085c6817cc30caabba381deb8d204c1c766" @@ -17009,23 +17019,6 @@ eth-ens-namehash@^1.0.2: idna-uts46 "^1.0.1" js-sha3 "^0.5.7" -eth-json-rpc-middleware@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-9.0.1.tgz#193cb05174739fb736737bbbf992e13010c4b44e" - integrity sha512-5yLNjkedXA4LTIBzzU2f7aHFJqANPsc5qCdOZy6T2p7mlDLW+0q0YBQg6Lx4sHdamOWUnJwvm70qzPAqst5zSg== - 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" - eth-method-registry@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eth-method-registry/-/eth-method-registry-4.0.0.tgz#2c2b78d5711dbd8f2c8f5e2de85a7a05f9769800" @@ -20973,13 +20966,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -21025,11 +21011,6 @@ jsonfile@^6.0.1, jsonfile@^6.1.0: optionalDependencies: graceful-fs "^4.1.6" -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - jsonpath-plus@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-7.2.0.tgz#7ad94e147b3ed42f7939c315d2b9ce490c5a3899" @@ -26607,10 +26588,10 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1, safe-stable-stringify@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== +safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1, safe-stable-stringify@^2.3.2, safe-stable-stringify@^2.4.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" From afb8576bcdc2d71f84a8ec08c15bdf0480cfa9f7 Mon Sep 17 00:00:00 2001 From: Xiaoming Wang <7315988+dawnseeker8@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:22:15 +0800 Subject: [PATCH 24/90] fix: fix 11836 wrong accounts in 2 ledger devices (#11967) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR will fix #11835 issue, the details of this PR change include following: 1. Fix the useBluetoothDevices.ts infinitely loop to setDevices due to devices properties in outside scope of observable inside next() function (devices always is empty object) 2. Fix the scan.tsx component which always select the first devices due to above change. ## **Related issues** Fixes: #11835 ## **Manual testing steps** 1. Install MM 2. Recover from SRP 3. Pair Ledger Nano X to MM 4. Pair Ledger Stax to MM 5. Select Ledger Nano X and verify account list derived from device 6. Select Ledger Stax and verify account list derived from device Expected:- 2 different account lists for each device ## **Screenshots/Recordings** ### **Before** https://api.zenhub.com/attachedFiles/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBOFJUQnc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--0c57025402bf0df5c50f0a5247c29ddf56cc7e60/RPReplay_Final1729159957.MP4 ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../Views/LedgerConnect/Scan.test.tsx | 45 ++++++++++++++ app/components/Views/LedgerConnect/Scan.tsx | 8 +-- .../hooks/Ledger/useBluetoothDevices.test.ts | 61 +++++++++++++++++++ .../hooks/Ledger/useBluetoothDevices.ts | 55 +++++++++-------- 4 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 app/components/hooks/Ledger/useBluetoothDevices.test.ts diff --git a/app/components/Views/LedgerConnect/Scan.test.tsx b/app/components/Views/LedgerConnect/Scan.test.tsx index 3052547651e..b0e1620232b 100644 --- a/app/components/Views/LedgerConnect/Scan.test.tsx +++ b/app/components/Views/LedgerConnect/Scan.test.tsx @@ -5,6 +5,9 @@ import useBluetoothDevices from '../../hooks/Ledger/useBluetoothDevices'; import useBluetoothPermissions from '../../hooks/useBluetoothPermissions'; import useBluetooth from '../../hooks/Ledger/useBluetooth'; import { BluetoothPermissionErrors } from '../../../core/Ledger/ledgerErrors'; +import { fireEvent } from '@testing-library/react-native'; +import { SELECT_DROP_DOWN } from '../../UI/SelectOptionSheet/constants'; +import { NavigationProp, ParamListBase, useNavigation } from '@react-navigation/native'; jest.mock('../../hooks/Ledger/useBluetooth'); jest.mock('../../hooks/Ledger/useBluetoothDevices'); @@ -19,6 +22,11 @@ jest.mock('@react-navigation/native', () => ({ useNavigation: jest.fn(), })); +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigation: jest.fn(), +})); + describe('Scan', () => { beforeEach(() => { jest.clearAllMocks(); @@ -175,4 +183,41 @@ describe('Scan', () => { expect(onScanningErrorStateChanged).toHaveBeenCalled(); }); + + it('calls onValueChange when select different device', () => { + const device1 = { + id: 'device1', + name: 'Device 1', + }; + const device2 = { + id: 'device2', + name: 'Device 2', + }; + + const onDeviceSelected = jest.fn(); + + const navigateMock = { + navigate: jest.fn().mockImplementation(() => {onDeviceSelected(device2)}), + } as unknown as NavigationProp; + jest.mocked(useNavigation).mockReturnValue(navigateMock); + + jest.mocked(useBluetoothDevices).mockReturnValue({ + devices: [device1, device2], + deviceScanError: false, + }); + + const {getByTestId} = renderWithProvider( + , + ); + expect(onDeviceSelected).toHaveBeenCalledWith(device1); + + fireEvent.press(getByTestId(SELECT_DROP_DOWN)); + + expect(onDeviceSelected).toHaveBeenCalledWith(device2); + }); + }); diff --git a/app/components/Views/LedgerConnect/Scan.tsx b/app/components/Views/LedgerConnect/Scan.tsx index ae84da05dd4..af0bdf45a63 100644 --- a/app/components/Views/LedgerConnect/Scan.tsx +++ b/app/components/Views/LedgerConnect/Scan.tsx @@ -86,12 +86,12 @@ const Scan = ({ ]); useEffect(() => { - // first device is selected by default - if (devices?.length > 0) { + // first device is selected by default if not selectedDevice is set + if (devices?.length > 0 && !selectedDevice) { + setSelectedDevice(devices[0]); onDeviceSelected(devices[0]); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [devices]); + }, [devices, onDeviceSelected, selectedDevice]); useEffect(() => { if (bluetoothPermissionError && !permissionErrorShown) { diff --git a/app/components/hooks/Ledger/useBluetoothDevices.test.ts b/app/components/hooks/Ledger/useBluetoothDevices.test.ts new file mode 100644 index 00000000000..5fc602d909b --- /dev/null +++ b/app/components/hooks/Ledger/useBluetoothDevices.test.ts @@ -0,0 +1,61 @@ +import { renderHook } from '@testing-library/react-hooks'; +import useBluetoothDevices from './useBluetoothDevices'; +import { Observable } from 'rxjs'; + +describe('useBluetoothDevices', () => { + let subscribeMock: jest.Mock; + + beforeEach(() => { + subscribeMock = jest.fn(); + jest.spyOn(Observable.prototype, 'subscribe').mockImplementation(subscribeMock); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('returns empty devices and no error when permissions are false', () => { + const { result } = renderHook(() => useBluetoothDevices(false, true)); + + expect(result.current.devices).toEqual([]); + expect(result.current.deviceScanError).toBe(false); + }); + + it('returns empty devices and no error when bluetooth is off', () => { + const { result } = renderHook(() => useBluetoothDevices(true, false)); + + expect(result.current.devices).toEqual([]); + expect(result.current.deviceScanError).toBe(false); + }); + + it('returns expected device and no error when permissions and bluetooth are on and devices scan return devices', async () => { + + const expectedDevice1 = { + id: '1', + name: 'Device 1', + }; + + // Mock `listen` to simulate device discovery + subscribeMock.mockImplementation(({ next }) => { + next({ + type: 'add', + descriptor: expectedDevice1, + }); + }); + const { result } = renderHook(() => useBluetoothDevices(true, true)); + + expect(result.current.devices).toEqual([expectedDevice1]); + expect(result.current.deviceScanError).toBe(false); + }); + + it('returns error when device scan fails', async () => { + // Mock `listen` to simulate device discovery + subscribeMock.mockImplementation(({ error }) => { + error('Error'); + }); + const { result } = renderHook(() => useBluetoothDevices(true, true)); + + expect(result.current.devices).toEqual([]); + expect(result.current.deviceScanError).toBe(true); + }); +}); diff --git a/app/components/hooks/Ledger/useBluetoothDevices.ts b/app/components/hooks/Ledger/useBluetoothDevices.ts index 0ee1dcec990..3a304c6c914 100644 --- a/app/components/hooks/Ledger/useBluetoothDevices.ts +++ b/app/components/hooks/Ledger/useBluetoothDevices.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'; import { Observable, Observer, Subscription } from 'rxjs'; export interface BluetoothDevice { @@ -20,44 +21,33 @@ export interface BluetoothInterface { close(): void; } +export interface ObservableEventType { + type: string, + descriptor: BluetoothDevice, + deviceModel: never, +} + const useBluetoothDevices = ( hasBluetoothPermissions: boolean, bluetoothOn: boolean, ) => { const [devices, setDevices] = useState>({}); const [deviceScanError, setDeviceScanError] = useState(false); + const [observableEvent, setObservableEvent] = useState(); // Initiate scanning and pairing if bluetooth is enabled useEffect(() => { let subscription: Subscription; if (hasBluetoothPermissions && bluetoothOn) { - import('@ledgerhq/react-native-hw-transport-ble').then( - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (bluetoothInterface: any) => { - subscription = new Observable( - bluetoothInterface.default.listen, - ).subscribe({ - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - next: (e: any) => { - const deviceFound = devices[e?.descriptor.id]; - - if (e.type === 'add' && !deviceFound) { - setDevices((prevValues) => ({ - ...prevValues, - [e.descriptor.id]: e.descriptor, - })); - setDeviceScanError(false); - } - }, - error: (_error) => { - setDeviceScanError(true); - }, - }); + subscription = new Observable(TransportBLE.listen).subscribe({ + next: (e: ObservableEventType) => { + setObservableEvent(e); + }, + error: (_error) => { + setDeviceScanError(true); }, - ); + }); } return () => { @@ -66,6 +56,21 @@ const useBluetoothDevices = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [hasBluetoothPermissions, bluetoothOn]); + useEffect(() =>{ + if (observableEvent?.descriptor) { + const btDevice = observableEvent.descriptor; + const deviceFound = devices[btDevice.id]; + + if (observableEvent.type === 'add' && !deviceFound) { + setDevices((prevValues) => ({ + ...prevValues, + [btDevice.id]: btDevice, + })); + setDeviceScanError(false); + } + } + }, [observableEvent, devices]); + return { deviceScanError, devices: Object.values(devices), From 36d25356e674a8b1a295d101938a4f138141d190 Mon Sep 17 00:00:00 2001 From: Kaihuang72490 <147628638+Kaihuang72490@users.noreply.github.com> Date: Tue, 29 Oct 2024 08:47:23 -0700 Subject: [PATCH 25/90] feat: add favorites to browser menu (#12060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We're adding in a "Go to Favorites" option into the browser menu so users can navigate to https://home.metamask.io, allowing them to access their previous favorites pages. After switching to the Portfolio dapps for a user's homepage, we received a decent amount of user feedback wanting this feature back in. ## **Related issues** Fixes: ## **Manual testing steps** 1. Open the in-app browser 2. Navigate to any website that's not https://home.metamask.io 3. Open the browser menu by tapping on the "more" icon 4. See the new "Go to Favorites" option, tap that. 5. Confirm that the user is taken to https://home.metamask.io ## **Screenshots/Recordings** ### **Before** ![IMG_8936](https://github.com/user-attachments/assets/36f65f0c-7929-4058-98ba-5800aec70be5) ### **After** ![Screenshot 2024-10-28 at 11 13 04 AM](https://github.com/user-attachments/assets/68a2898e-2a72-43ee-8572-155a7b5a2028) Actual https://github.com/user-attachments/assets/e6aabfd6-3746-4075-ad47-b8140afbc3fd ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Signed-off-by: Kai Huang Co-authored-by: Cal-L Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> Co-authored-by: Cal Leung --- app/components/Views/BrowserTab/index.js | 39 +++++++++++++++++-- app/core/Analytics/MetaMetrics.events.ts | 1 + locales/languages/en.json | 1 + .../BrowserScreen/OptionMenu.testIds.js | 2 + 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index b602a19466c..7910f9b52ca 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -80,6 +80,7 @@ import Routes from '../../../constants/navigation/Routes'; import generateTestId from '../../../../wdio/utils/generateTestId'; import { ADD_FAVORITES_OPTION, + OPEN_FAVORITES_OPTION, MENU_ID, NEW_TAB_OPTION, OPEN_IN_BROWSER_OPTION, @@ -298,7 +299,8 @@ export const BrowserTab = (props) => { const { colors, shadows } = useTheme(); const styles = createStyles(colors, shadows); const favicon = useFavicon(url.current); - const { trackEvent, isEnabled, getMetaMetricsId } = useMetrics(); + const { trackEvent, isEnabled, getMetaMetricsId, createEventBuilder } = + useMetrics(); /** * Is the current tab the active tab */ @@ -978,6 +980,18 @@ export const BrowserTab = (props) => { trackEvent(MetaMetricsEvents.DAPP_HOME); }; + /** + * Go to favorites page + */ + const goToFavorites = async () => { + toggleOptionsIfNeeded(); + if (url.current === OLD_HOMEPAGE_URL_HOST) return reload(); + await go(OLD_HOMEPAGE_URL_HOST); + trackEvent( + createEventBuilder(MetaMetricsEvents.DAPP_GO_TO_FAVORITES).build(), + ); + }; + /** * Handle url input submit */ @@ -1288,11 +1302,29 @@ export const BrowserTab = (props) => { trackReloadEvent(); }; + /** + * Renders Go to Favorites option + */ + const renderGoToFavorites = () => ( + + ); + /** * Render non-homepage options menu */ const renderNonHomeOptions = () => { - if (isHomepage()) return null; + if (isHomepage()) return renderGoToFavorites(); return ( @@ -1311,7 +1343,7 @@ export const BrowserTab = (props) => { {!isBookmark() && ( )} + {renderGoToFavorites()}