From 3ab24661035b57aa69ece32d695461c53588ea6d Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 05:51:38 +0000 Subject: [PATCH 01/11] Convert ganache-contract-address-registry.js to TypeScript --- ...ess-registry.js => ganache-contract-address-registry.ts} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename app/util/test/{ganache-contract-address-registry.js => ganache-contract-address-registry.ts} (74%) diff --git a/app/util/test/ganache-contract-address-registry.js b/app/util/test/ganache-contract-address-registry.ts similarity index 74% rename from app/util/test/ganache-contract-address-registry.js rename to app/util/test/ganache-contract-address-registry.ts index 5659401a236..db06e16298c 100644 --- a/app/util/test/ganache-contract-address-registry.js +++ b/app/util/test/ganache-contract-address-registry.ts @@ -3,7 +3,7 @@ * a local blockchain instance ran by Ganache. */ class GanacheContractAddressRegistry { - #addresses = {}; + #addresses: Record = {}; /** * Store new contract address in key:value pair. @@ -11,7 +11,7 @@ class GanacheContractAddressRegistry { * @param contractName * @param contractAddress */ - storeNewContractAddress(contractName, contractAddress) { + storeNewContractAddress(contractName: string, contractAddress: string): void { this.#addresses[contractName] = contractAddress; } @@ -20,7 +20,7 @@ class GanacheContractAddressRegistry { * * @param contractName */ - getContractAddress(contractName) { + getContractAddress(contractName: string): string | undefined { return this.#addresses[contractName]; } } From 3c386abebbf49a485495422b897d0f14fe6ba3d0 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 06:00:26 +0000 Subject: [PATCH 02/11] Remove return types from methods in ganache-contract-address-registry.ts --- app/util/test/ganache-contract-address-registry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/util/test/ganache-contract-address-registry.ts b/app/util/test/ganache-contract-address-registry.ts index db06e16298c..517f5c0e613 100644 --- a/app/util/test/ganache-contract-address-registry.ts +++ b/app/util/test/ganache-contract-address-registry.ts @@ -11,7 +11,7 @@ class GanacheContractAddressRegistry { * @param contractName * @param contractAddress */ - storeNewContractAddress(contractName: string, contractAddress: string): void { + storeNewContractAddress(contractName: string, contractAddress: string) { this.#addresses[contractName] = contractAddress; } @@ -20,7 +20,7 @@ class GanacheContractAddressRegistry { * * @param contractName */ - getContractAddress(contractName: string): string | undefined { + getContractAddress(contractName: string) { return this.#addresses[contractName]; } } From 22a566ce9faf3ddfbd62731b8e07d3797144295f Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 19:39:19 -0500 Subject: [PATCH 03/11] chore(js-ts): Convert app/util/bytes.js to TypeScript (#11275) # Pull Request Description ## Motivation This pull request aims to convert the `bytes.js` file to TypeScript, improving type safety and maintainability of the codebase. ## Context As part of our ongoing efforts to migrate the MetaMask Mobile codebase to TypeScript, we are converting JavaScript files to TypeScript one at a time. This PR focuses on the `bytes.js` utility file. ## Changes - Renamed `app/util/bytes.js` to `app/util/bytes.ts` - Added type annotations for the function parameter and return value - Refactored the `for` loop to a `for-of` loop to address potential linting issues - Created `notes.md` to track TODOs and type-related considerations ## Files Changed 1. `app/util/bytes.ts` (renamed from `bytes.js`) 2. `notes.md` (new file) ## Testing - Ran `yarn tsc` to ensure successful TypeScript compilation - Ran `yarn lint` to check for any linting issues ## Notes - The `value` parameter type is currently set to `Uint8Array`, but we may need to consider allowing `number[]` as well in the future. - All existing functionality should remain unchanged. ## Checklist - [x] Code follows the MetaMask Coding Standards - [x] Tests for the changes have been added (if applicable) - [x] All tests pass - [x] Lint and prettier checks pass - [ ] This PR is ready for review ## Link to Devin run https://preview.devin.ai/devin/0a3389f83f8d4560bdce6a8a5a186bdd ## Additional Information This pull request was created by Devin at the request of Moritz. If you have any feedback, you can leave comments in the PR and I'll address them in the app! --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- app/util/{bytes.js => bytes.ts} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename app/util/{bytes.js => bytes.ts} (72%) diff --git a/app/util/bytes.js b/app/util/bytes.ts similarity index 72% rename from app/util/bytes.js rename to app/util/bytes.ts index ac04d050c20..3d046a30889 100644 --- a/app/util/bytes.js +++ b/app/util/bytes.ts @@ -5,11 +5,10 @@ * * @returns - Hex string */ -export default function byteArrayToHex(value) { +export default function byteArrayToHex(value: Uint8Array): string { const HexCharacters = '0123456789abcdef'; const result = []; - for (let i = 0; i < value.length; i++) { - const v = value[i]; + for (const v of value) { result.push(HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f]); } return '0x' + result.join(''); From bfa34c0811cbd2d5fb725f78774c59f7e0060b69 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:02:35 +0100 Subject: [PATCH 04/11] fix: refactor Logger usage (#11430) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR refactor the usage of Logger util as requested in [this](https://github.com/MetaMask/metamask-mobile/pull/11250#discussion_r1773665264) comment. ## **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. --- .../services/NotificationService.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/app/util/notifications/services/NotificationService.ts b/app/util/notifications/services/NotificationService.ts index d8d6c53ae0f..782de0dec1a 100644 --- a/app/util/notifications/services/NotificationService.ts +++ b/app/util/notifications/services/NotificationService.ts @@ -47,13 +47,10 @@ class NotificationsService { return map; }, new Map()); } catch (e) { - if (e instanceof Error) { - Logger.error(e, strings('notifications.error_checking_permission')); - } else { - Logger.error( - new Error(strings('notifications.error_checking_permission')), - ); - } + Logger.error( + e as Error, + strings('notifications.error_checking_permission'), + ); return new Map(); } } @@ -135,13 +132,10 @@ class NotificationsService { strings('notifications.prompt_desc'), ); } catch (e) { - if (e instanceof Error) { - Logger.error(e, strings('notifications.error_checking_permission')); - } else { - Logger.error( - new Error(strings('notifications.error_checking_permission')), - ); - } + Logger.error( + e as Error, + strings('notifications.error_checking_permission'), + ); } } openSystemSettings() { From 681c0424e5fc0f63ddbdddc53fae12756b0bf414 Mon Sep 17 00:00:00 2001 From: Cal Leung Date: Wed, 25 Sep 2024 07:44:14 -0700 Subject: [PATCH 05/11] chore: Add skip label to bypass sonarcloud (#11425) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Adds logic in the `sonar-cloud-quality-gate-status` step in the CI that checks for the existence of `skip-sonar-cloud` label. If it exists, the step is bypassed and passes. If the label doesn't exist, it checks the sonar cloud quality gate status as usual. Also removes the redundant `sonar-cloud` dependency in the `all-jobs-pass` step ## **Related issues** Fixes: #11403 ## **Manual testing steps** - Apply `skip-sonar-cloud` label - Manually re-run `ci.yml` jobs - Notice the `sonar-cloud-quality-gate-status` step logs that it is skipped and the status checks is green - Afterwards, remove `skip-sonar-cloud` label - Manually re-run `ci.yml` jobs - Notice the `sonar-cloud-quality-gate-status` step runs as usual ## **Screenshots/Recordings** ### **Before** ### **After** With label applied https://github.com/MetaMask/metamask-mobile/actions/runs/11026106803/job/30622332596?pr=11425 Without label applied **https://github.com/MetaMask/metamask-mobile/actions/runs/11026106803/job/30623782793** ## **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. --- .github/workflows/ci.yml | 54 ++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6dc2626eae8..64bd5bea831 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -222,6 +222,10 @@ jobs: uses: actions/checkout@v3 - name: SonarCloud Quality Gate Status id: sonar-status + env: + REPO: ${{ github.repository }} + ISSUE_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Skip step if event is a PR if [[ "${{ github.event_name }}" != "pull_request" ]]; then @@ -229,31 +233,40 @@ jobs: exit 0 fi - sleep 30 + # Bypass step if skip-sonar-cloud label is found + LABEL=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$REPO/issues/$ISSUE_NUMBER/labels" | \ + jq -r '.[] | select(.name=="skip-sonar-cloud") | .name') - PROJECT_KEY="metamask-mobile" - PR_NUMBER="${{ github.event.pull_request.number }}" - SONAR_TOKEN="${{ secrets.SONAR_TOKEN }}" + if [[ "$LABEL" == "skip-sonar-cloud" ]]; then + echo "skip-sonar-cloud label found. Skipping SonarCloud Quality Gate check." + else + sleep 30 - if [ -z "$PR_NUMBER" ]; then - echo "No pull request number found. Failing the check." - exit 1 - fi + PROJECT_KEY="metamask-mobile" + PR_NUMBER="${{ github.event.pull_request.number }}" + SONAR_TOKEN="${{ secrets.SONAR_TOKEN }}" - RESPONSE=$(curl -s -u "$SONAR_TOKEN:" \ - "https://sonarcloud.io/api/qualitygates/project_status?projectKey=$PROJECT_KEY&pullRequest=$PR_NUMBER") - echo "SonarCloud API Response: $RESPONSE" + if [ -z "$PR_NUMBER" ]; then + echo "No pull request number found. Failing the check." + exit 1 + fi - STATUS=$(echo "$RESPONSE" | jq -r '.projectStatus.status') + RESPONSE=$(curl -s -u "$SONAR_TOKEN:" \ + "https://sonarcloud.io/api/qualitygates/project_status?projectKey=$PROJECT_KEY&pullRequest=$PR_NUMBER") + echo "SonarCloud API Response: $RESPONSE" - if [[ "$STATUS" == "ERROR" ]]; then - echo "Quality Gate failed." - exit 1 - elif [[ "$STATUS" == "OK" ]]; then - echo "Quality Gate passed." - else - echo "Could not determine Quality Gate status." - exit 1 + STATUS=$(echo "$RESPONSE" | jq -r '.projectStatus.status') + + if [[ "$STATUS" == "ERROR" ]]; then + echo "Quality Gate failed." + exit 1 + elif [[ "$STATUS" == "OK" ]]; then + echo "Quality Gate passed." + else + echo "Could not determine Quality Gate status." + exit 1 + fi fi check-workflows: name: Check workflows @@ -277,7 +290,6 @@ jobs: scripts, unit-tests, check-workflows, - sonar-cloud, js-bundle-size-check, sonar-cloud-quality-gate-status, ] From 4fe28c70ce52740c4afee4e58421f92045fe2165 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:15:17 +0100 Subject: [PATCH 06/11] feat: add feature announcements channel for android (#11427) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR adds ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID for AndroidChannels. ## **Related issues** Fixes: [11415](https://github.com/MetaMask/metamask-mobile/issues/11415) ## **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. --- app/util/notifications/androidChannels.test.ts | 2 +- app/util/notifications/androidChannels.ts | 3 ++- app/util/notifications/settings/storage/constants.ts | 1 + app/util/notifications/settings/storage/contants.test.ts | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/util/notifications/androidChannels.test.ts b/app/util/notifications/androidChannels.test.ts index 49e3a28b8ad..c0cb6a45412 100644 --- a/app/util/notifications/androidChannels.test.ts +++ b/app/util/notifications/androidChannels.test.ts @@ -26,7 +26,7 @@ describe('notificationChannels', () => { it('should have the correct properties for the second channel', () => { const secondChannel: MetaMaskAndroidChannel = notificationChannels[1]; expect(secondChannel).toEqual({ - id: ChannelId.DEFAULT_NOTIFICATION_CHANNEL_ID, + id: ChannelId.ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID, name: 'MetaMask Announcement', lights: false, vibration: false, diff --git a/app/util/notifications/androidChannels.ts b/app/util/notifications/androidChannels.ts index 1bc1de98c72..4841cb7e1a5 100644 --- a/app/util/notifications/androidChannels.ts +++ b/app/util/notifications/androidChannels.ts @@ -2,6 +2,7 @@ import { AndroidChannel, AndroidImportance } from '@notifee/react-native'; export enum ChannelId { DEFAULT_NOTIFICATION_CHANNEL_ID = 'DEFAULT_NOTIFICATION_CHANNEL_ID', + ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID = 'ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID', } export interface MetaMaskAndroidChannel extends AndroidChannel { @@ -21,7 +22,7 @@ export const notificationChannels = [ subtitle: 'Transaction Complete', } as MetaMaskAndroidChannel, { - id: ChannelId.DEFAULT_NOTIFICATION_CHANNEL_ID, + id: ChannelId.ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID, name: 'MetaMask Announcement', lights: false, vibration: false, diff --git a/app/util/notifications/settings/storage/constants.ts b/app/util/notifications/settings/storage/constants.ts index fcf857060a4..f3bc4c2fb5c 100644 --- a/app/util/notifications/settings/storage/constants.ts +++ b/app/util/notifications/settings/storage/constants.ts @@ -6,6 +6,7 @@ export const STORAGE_IDS = { PUSH_NOTIFICATIONS_PROMPT_TIME: 'pushNotificationsPromptTime', DEVICE_ID_STORAGE_KEY: 'pns:deviceId', DEFAULT_NOTIFICATION_CHANNEL_ID: 'DEFAULT_NOTIFICATION_CHANNEL_ID', + ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID: 'ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID', DEFAULT_PUSH_NOTIFICATION_CHANNEL_PRIORITY: 'high', REQUEST_PERMISSION_ASKED: 'REQUEST_PERMISSION_ASKED', REQUEST_PERMISSION_GRANTED: 'REQUEST_PERMISSION_GRANTED', diff --git a/app/util/notifications/settings/storage/contants.test.ts b/app/util/notifications/settings/storage/contants.test.ts index 347cfb4b87f..efb2cf68f91 100644 --- a/app/util/notifications/settings/storage/contants.test.ts +++ b/app/util/notifications/settings/storage/contants.test.ts @@ -10,6 +10,8 @@ describe('constants', () => { PUSH_NOTIFICATIONS_PROMPT_TIME: 'pushNotificationsPromptTime', DEVICE_ID_STORAGE_KEY: 'pns:deviceId', DEFAULT_NOTIFICATION_CHANNEL_ID: 'DEFAULT_NOTIFICATION_CHANNEL_ID', + ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID: + 'ANNOUNCEMENT_NOTIFICATION_CHANNEL_ID', DEFAULT_PUSH_NOTIFICATION_CHANNEL_PRIORITY: 'high', REQUEST_PERMISSION_ASKED: 'REQUEST_PERMISSION_ASKED', REQUEST_PERMISSION_GRANTED: 'REQUEST_PERMISSION_GRANTED', From 1e0b5827c4e1b35c6f536db479323d3c5a9a83d5 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Wed, 25 Sep 2024 19:08:05 +0100 Subject: [PATCH 07/11] feat: add timeout handler (#11429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR adds a withTimeout wrapper on notifee async calls to avoid get blocked in case a call doesn't resolve quickly. This was a comment from [this PR](https://github.com/MetaMask/metamask-mobile/pull/11250#discussion_r1773684001) ## **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. --- app/util/notifications/methods/common.ts | 7 +++++++ .../services/NotificationService.test.ts | 12 ++++++++---- .../services/NotificationService.ts | 18 +++++++++++------- locales/languages/en.json | 6 +++--- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/util/notifications/methods/common.ts b/app/util/notifications/methods/common.ts index c7ac73eeacd..171d150f517 100644 --- a/app/util/notifications/methods/common.ts +++ b/app/util/notifications/methods/common.ts @@ -474,3 +474,10 @@ export const getUsdAmount = (amount: string, decimals: string, usd: string) => { export const hasInitialNotification = async () => Boolean(await notifee.getInitialNotification()); + +export function withTimeout(promise: Promise, ms: number): Promise { + const timeout = new Promise((_, reject) => + setTimeout(() => reject(new Error(strings('notifications.timeout'))), ms), + ); + return Promise.race([promise, timeout]); +} diff --git a/app/util/notifications/services/NotificationService.test.ts b/app/util/notifications/services/NotificationService.test.ts index 9816f9f99f4..e40e78dd47e 100644 --- a/app/util/notifications/services/NotificationService.test.ts +++ b/app/util/notifications/services/NotificationService.test.ts @@ -83,10 +83,14 @@ describe('NotificationsService', () => { expect(notifee.createChannel).toHaveBeenCalledWith(channel); }); - it('should return authorized from getAllPermissions', async () => { - const result = await NotificationsService.getAllPermissions(); - expect(result.permission).toBe('authorized'); - }); + it.concurrent( + 'should return authorized from getAllPermissions', + async () => { + const result = await NotificationsService.getAllPermissions(); + expect(result.permission).toBe('authorized'); + }, + 10000, + ); it('should return authorized from requestPermission ', async () => { const result = await NotificationsService.requestPermission(); diff --git a/app/util/notifications/services/NotificationService.ts b/app/util/notifications/services/NotificationService.ts index 782de0dec1a..40b72e0a48c 100644 --- a/app/util/notifications/services/NotificationService.ts +++ b/app/util/notifications/services/NotificationService.ts @@ -19,6 +19,7 @@ import { mmStorage } from '../settings'; import { STORAGE_IDS } from '../settings/storage/constants'; import { store } from '../../../store'; import Logger from '../../../util/Logger'; +import { withTimeout } from '../methods'; interface AlertButton { text: string; @@ -56,18 +57,21 @@ class NotificationsService { } async getAllPermissions(shouldOpenSettings = true) { - const promises = [] as Promise[]; - notificationChannels.forEach((channel: AndroidChannel) => { - promises.push(this.createChannel(channel)); - }); + const promises: Promise[] = notificationChannels.map( + (channel: AndroidChannel) => + withTimeout(this.createChannel(channel), 5000), + ); await Promise.allSettled(promises); - const permission = await this.requestPermission(); - const blockedNotifications = await this.getBlockedNotifications(); + const permission = await withTimeout(this.requestPermission(), 5000); + const blockedNotifications = await withTimeout( + this.getBlockedNotifications(), + 5000, + ); if ( (permission !== 'authorized' || blockedNotifications.size !== 0) && shouldOpenSettings ) { - this.requestPushNotificationsPermission(); + await this.requestPushNotificationsPermission(); } return { permission, blockedNotifications }; } diff --git a/locales/languages/en.json b/locales/languages/en.json index 71d0ac0b1ef..faf48beb6b5 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -2077,6 +2077,7 @@ "back_to_safety": "Back to safety" }, "notifications": { + "timeout": "Timeout", "no_date": "Unknown", "yesterday": "Yesterday", "staked": "Staked", @@ -3230,7 +3231,6 @@ "ledger_legacy_label": " (legacy)", "blind_sign_error": "Blind signing error", "blind_sign_error_message": "Blind signing is not enabled on your Ledger device. Please enable it in the settings." - }, "account_actions": { "edit_name": "Edit account name", @@ -3298,7 +3298,7 @@ "enter_amount": "Enter amount", "review": "Review", "not_enough_eth": "Not enough ETH", - "balance":"Balance" + "balance": "Balance" }, "default_settings": { "title": "Your Wallet is ready", @@ -3357,4 +3357,4 @@ "tooltip": "Expected yearly increase in the value of your stake, based on the reward rate over the past week." } } -} +} \ No newline at end of file From e661ad71540b6d7becda08deac621feb495b3156 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Wed, 25 Sep 2024 19:23:02 +0100 Subject: [PATCH 08/11] fix: react native quick crypto ios build bug (#11443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR fixes a bug introduces on iOS builds using react-native-quick-crypto as documented [here](https://github.com/margelo/react-native-quick-crypto/issues/244) ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** Successful build: https://app.bitrise.io/build/076ad837-6e35-4165-a4f2-14c5754ad1d3 ## **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. --- ios/Podfile | 3 +++ ios/Podfile.lock | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ios/Podfile b/ios/Podfile index 4282bf754f0..759ce5f2e02 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -96,6 +96,9 @@ def common_target_logic # use_frameworks! pod 'Permission-BluetoothPeripheral', :path => '../node_modules/react-native-permissions/ios/BluetoothPeripheral' pod 'GzipSwift' + + # Pod for fixing react-native-quick-crypto issue: https://github.com/margelo/react-native-quick-crypto/issues/244 + pod "OpenSSL-Universal", "= 1.1.1100" end target 'MetaMask' do diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9b4b80f9f4a..fa5cb9cc045 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1302,6 +1302,6 @@ SPEC CHECKSUMS: Yoga: 6f5ab94cd8b1ecd04b6e973d0bc583ede2a598cc YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 0e9407472193b5f7d5cfe4715c8f1f2c2fed42e5 +PODFILE CHECKSUM: 876298d4a106643492005466f7a314cd08711f4d COCOAPODS: 1.15.2 From eada60ca6bb48212b95c821dd4ebec8e84530dd2 Mon Sep 17 00:00:00 2001 From: EtherWizard33 <165834542+EtherWizard33@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:39:00 -0400 Subject: [PATCH 09/11] feat(3299): add tracking to network switching and confirmation (#11386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Adds tracking to the user requesting network switching as well as his press of the confirmation button. ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3299 ## **Manual testing steps** 1. Go to the in app browser and open have a connected dapp for example to ethereum main net 2. In the dapp select to change network, the modal will come up, thats when the tracking event if fire for user requesting a network change 3. Confirm the network change by pressing the button, this corresponds to the confirm pressed tracked event ## **Screenshots/Recordings** #### Mixpanel logs for the two events Mixpanel logs for the two events #### Network Switch Requested and Modal Shown | Interaction | Tracked event | |--------------|--------------| | Screenshot 2024-04-18 at 3 56 43 PM |Screenshot 2024-04-18 at 3 56 43 PM | #### Network Switch Confirm Pressed | **Interaction** | **Tracked event** | |--------------|--------------| | Screenshot 2024-04-18 at 3 56 43 PM |Screenshot 2024-04-18 at 3 56 43 PM | ## **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/SwitchCustomNetwork/index.js | 32 +++++++++++++++++-- .../UI/SwitchCustomNetwork/index.test.tsx | 16 ++++++++++ app/core/Analytics/MetaMetrics.events.ts | 8 +++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/app/components/UI/SwitchCustomNetwork/index.js b/app/components/UI/SwitchCustomNetwork/index.js index 1a3bf3eaea2..f6f63cf3e87 100644 --- a/app/components/UI/SwitchCustomNetwork/index.js +++ b/app/components/UI/SwitchCustomNetwork/index.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useMemo } from 'react'; import PropTypes from 'prop-types'; import StyledButton from '../StyledButton'; import { StyleSheet, View } from 'react-native'; @@ -8,8 +8,14 @@ import Device from '../../../util/device'; import Text from '../../Base/Text'; import { useTheme } from '../../../util/theme'; import { CommonSelectorsIDs } from '../../../../e2e/selectors/Common.selectors'; -import { isMultichainVersion1Enabled } from '../../../util/networks'; +import { + isMultichainVersion1Enabled, + getDecimalChainId, +} from '../../../util/networks'; import PermissionSummary from '../PermissionsSummary'; +import { MetaMetricsEvents } from '../../../core/Analytics'; +import { useNetworkInfo } from '../../../selectors/selectedNetworkController'; +import { useMetrics } from '../../../components/hooks/useMetrics'; const createStyles = (colors) => StyleSheet.create({ @@ -90,11 +96,33 @@ const SwitchCustomNetwork = ({ }) => { const { colors } = useTheme(); const styles = createStyles(colors); + const { trackEvent } = useMetrics(); + + const { networkName } = useNetworkInfo( + new URL(currentPageInformation.url).hostname, + ); + + const trackingData = useMemo( + () => ({ + chain_id: getDecimalChainId(customNetworkInformation.chainId), + from_network: networkName, + to_network: customNetworkInformation.chainName, + }), + [customNetworkInformation, networkName], + ); + + useEffect(() => { + trackEvent( + MetaMetricsEvents.NETWORK_SWITCH_REQUESTED_AND_MODAL_SHOWN, + trackingData, + ); + }, [trackEvent, trackingData]); /** * Calls onConfirm callback and analytics to track connect confirmed event */ const confirm = () => { + trackEvent(MetaMetricsEvents.NETWORK_SWITCH_CONFIRM_PRESSED, trackingData); onConfirm && onConfirm(); }; diff --git a/app/components/UI/SwitchCustomNetwork/index.test.tsx b/app/components/UI/SwitchCustomNetwork/index.test.tsx index daec075e1e3..4a338b39b96 100644 --- a/app/components/UI/SwitchCustomNetwork/index.test.tsx +++ b/app/components/UI/SwitchCustomNetwork/index.test.tsx @@ -1,13 +1,29 @@ import React from 'react'; import SwitchCustomNetwork from './'; import renderWithProvider from '../../../util/test/renderWithProvider'; +import { backgroundState } from '../../../util/test/initial-root-state'; +import { MOCK_ACCOUNTS_CONTROLLER_STATE } from '../../../util/test/accountsControllerTestUtils'; + +const mockInitialState = { + wizard: { + step: 1, + }, + engine: { + backgroundState: { + ...backgroundState, + AccountsController: MOCK_ACCOUNTS_CONTROLLER_STATE, + }, + }, +}; describe('SwitchCustomNetwork', () => { it('should render correctly', () => { const { toJSON } = renderWithProvider( , + { state: mockInitialState }, ); expect(toJSON()).toMatchSnapshot(); }); diff --git a/app/core/Analytics/MetaMetrics.events.ts b/app/core/Analytics/MetaMetrics.events.ts index 0a61dbc6f16..5b972ea1130 100644 --- a/app/core/Analytics/MetaMetrics.events.ts +++ b/app/core/Analytics/MetaMetrics.events.ts @@ -80,6 +80,8 @@ enum EVENT_NAME { // Network NETWORK_SWITCHED = 'Network Switched', + NETWORK_SWITCH_REQUESTED_AND_MODAL_SHOWN = 'Network Switch Requested and Modal Shown', + NETWORK_SWITCH_CONFIRM_PRESSED = 'Network Switch Confirm Pressed', NETWORK_ADDED = 'Network Added', NETWORK_REQUESTED = 'Network Requested', NETWORK_REQUEST_REJECTED = 'Network Request Rejected', @@ -482,6 +484,12 @@ const events = { COLLECTIBLE_REMOVED: generateOpt(EVENT_NAME.COLLECTIBLE_REMOVED), CURRENCY_CHANGED: generateOpt(EVENT_NAME.CURRENCY_CHANGED), NETWORK_SWITCHED: generateOpt(EVENT_NAME.NETWORK_SWITCHED), + NETWORK_SWITCH_REQUESTED_AND_MODAL_SHOWN: generateOpt( + EVENT_NAME.NETWORK_SWITCH_REQUESTED_AND_MODAL_SHOWN, + ), + NETWORK_SWITCH_CONFIRM_PRESSED: generateOpt( + EVENT_NAME.NETWORK_SWITCH_CONFIRM_PRESSED, + ), NETWORK_ADDED: generateOpt(EVENT_NAME.NETWORK_ADDED), NETWORK_REQUESTED: generateOpt(EVENT_NAME.NETWORK_REQUESTED), NETWORK_REQUEST_REJECTED: generateOpt(EVENT_NAME.NETWORK_REQUEST_REJECTED), From fd702e9b2680177c0a56001410e5606b4ac89aa3 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 23:24:23 +0000 Subject: [PATCH 10/11] commit to trigger CI From 8ca86911060a1f58f9af4e64ce01fc4f005a5d44 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 23:29:27 +0000 Subject: [PATCH 11/11] commit to trigger CI