diff --git a/.eslintrc.js b/.eslintrc.js index edbe2143bb0..567466baec8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -73,6 +73,33 @@ module.exports = { '@metamask/design-tokens/color-no-hex': 'off', }, }, + { + files: [ + 'app/components/UI/Name/**/*.{js,ts,tsx}', + 'app/components/hooks/DisplayName/**/*.{js,ts,tsx}' + ], + rules: { + 'no-restricted-syntax': [ + 'error', + { + selector: `ImportSpecifier[imported.name=/${[ + 'selectChainId', + 'selectNetworkClientId', + 'selectNetworkStatus', + 'selectNickname', + 'selectProviderConfig', + 'selectProviderType', + 'selectRpcUrl', + 'selectSelectedNetworkClientId', + 'selectTicker' + ] + .map((method) => `(${method})`) + .join('|')}/]`, + message: 'Avoid using global network selectors in confirmations', + }, + ], + }, + }, ], globals: { diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d2f19a48bb..2833be9d189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Current Main Branch +## 7.34.1 - Nov 8, 2024 +### Fixed +- [#12205](https://github.com/MetaMask/metamask-mobile/pull/12205): fix: add contractBalances as dependency +- [#12236](https://github.com/MetaMask/metamask-mobile/pull/12236): fix: Add migration to fix NotificationServicesController bug (#12236) +- [#12228](https://github.com/MetaMask/metamask-mobile/pull/12228): fix: Update transaction-controller version + ## 7.34.0 - Oct 28, 2024 ### Added - [#11578](https://github.com/MetaMask/metamask-mobile/pull/11578): feat: 1653 first feature flag poc (#11578) @@ -101,7 +107,7 @@ ### Fixed - [#10952](https://github.com/MetaMask/metamask-mobile/pull/10952): refactor(ramp): update ramp copy (#10952) -## 7.33.2 - Oct 29, 2024 +## 7.33.1 - Oct 29, 2024 ### Fixed - [#12073](https://github.com/MetaMask/metamask-mobile/pull/12073): feat: Simulation re-trigger (#12073) diff --git a/README.md b/README.md index 08173a32791..92c2ef0d35a 100644 --- a/README.md +++ b/README.md @@ -39,44 +39,36 @@ git clone git@github.com:MetaMask/metamask-mobile.git && \ cd metamask-mobile ``` -### **Firebase Messaging Setup** +#### Firebase Messaging Setup MetaMask uses Firebase Cloud Messaging (FCM) to enable app communications. To integrate FCM, you’ll need configuration files for both iOS and Android platforms. -#### **Configuration Files Required** -- **`GoogleService-Info.plist`** (iOS) -- **`google-services.json`** (Android) +##### Internal Contributor instructions -These files are essential for FCM integration and are automatically generated when running: `yarn start:ios` or `yarn start:android` +1. Grab the `.js.env` file from 1Password, ask around for the correct vault. This file contains the `GOOGLE_SERVICES_B64_ANDROID` and `GOOGLE_SERVICES_B64_IOS` secrets that will be used to generate the relevant configuration files for IOS/Android. +2. [Install](./README.md#install-dependencies) and [run & start](./README.md#running-the-app) the application as documented below. -**External Contributors** +##### External Contributor instructions As an external contributor, you need to provide your own Firebase project configuration files: +- **`GoogleService-Info.plist`** (iOS) +- **`google-services.json`** (Android) 1. Create a Free Firebase Project - * Set up a Firebase project in the Firebase Console. - * Configure the project with a client package name matching `io.metamask`. + - Set up a Firebase project in the Firebase Console. + - Configure the project with a client package name matching `io.metamask` (IMPORTANT). 2. Add Configuration Files - * Update the `google-services.json` and `GoogleService-Info.plist` files in: - * `android/app` (for Android) - * `ios` directory (for iOS) - -In case you don't have FCM account, you can reference the instructions below. These instructions will generate the required `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` environment variables found in: `.ios.env`, `.js.env`, `.android.env`. They can be locally generated from examples files. - -**Internal Contributors** - -As an internal contributor, you can access the shared Firebase project config file from 1Password. Ask around for the correct vault. - -The values you should provide to `GOOGLE_SERVICES_B64_ANDROID` or `GOOGLE_SERVICES_B64_IOS` are the base64 encoded versions of the example Firebase project config files. These can also be generated locally: - -**For Android** + - Create/Update the `google-services.json` and `GoogleService-Info.plist` files in: + - `android/app/google-services.json` (for Android) + - `ios/GoogleServices/GoogleService-Info.plist` directory (for iOS) +3. Create the correct base64 environments variables. + ```bash -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 -``` +# Generate Android Base64 Version of Google Services +export GOOGLE_SERVICES_B64_ANDROID="$(base64 -w0 -i ./android/app/google-services.json)" && echo "export GOOGLE_SERVICES_B64_ANDROID=\"$GOOGLE_SERVICES_B64_ANDROID\"" | tee -a .js.env -**For iOS** -```bash -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 +# Generate IOS Base64 Version of Google Services +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 ``` [!CAUTION] @@ -85,7 +77,7 @@ export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleServi 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** +#### Install dependencies ```bash yarn setup diff --git a/android/app/build.gradle b/android/app/build.gradle index 3e466452e54..d579a4a7fc6 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 1475 - versionName "7.34.0" + versionCode 1482 + versionName "7.34.1" testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/component-library/components-temp/KeyValueRow/KeyValueLabel/KeyValueLabel.tsx b/app/component-library/components-temp/KeyValueRow/KeyValueLabel/KeyValueLabel.tsx index bfc064931ee..748463f59a0 100644 --- a/app/component-library/components-temp/KeyValueRow/KeyValueLabel/KeyValueLabel.tsx +++ b/app/component-library/components-temp/KeyValueRow/KeyValueLabel/KeyValueLabel.tsx @@ -35,6 +35,7 @@ const KeyValueRowLabel = ({ label, tooltip }: KeyValueRowLabelProps) => { const onNavigateToTooltipModal = () => { if (!hasTooltip) return; openTooltipModal(tooltip.title, tooltip.content); + tooltip?.onPress?.(); }; return ( diff --git a/app/component-library/components-temp/KeyValueRow/KeyValueRow.types.ts b/app/component-library/components-temp/KeyValueRow/KeyValueRow.types.ts index fc4e825921e..b04e893bd62 100644 --- a/app/component-library/components-temp/KeyValueRow/KeyValueRow.types.ts +++ b/app/component-library/components-temp/KeyValueRow/KeyValueRow.types.ts @@ -27,6 +27,10 @@ interface KeyValueRowTooltip { * @default TooltipSizes.Md */ size?: ButtonIconSizes; + /** + * Optional onPress handler + */ + onPress?: (...args: unknown[]) => unknown; } /** diff --git a/app/components/UI/Identicon/__snapshots__/index.test.tsx.snap b/app/components/UI/Identicon/__snapshots__/index.test.tsx.snap index 9707813bf99..06955be160d 100644 --- a/app/components/UI/Identicon/__snapshots__/index.test.tsx.snap +++ b/app/components/UI/Identicon/__snapshots__/index.test.tsx.snap @@ -1,83 +1,294 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Identicon should render correctly when provided address found in tokenList and iconUrl is available 1`] = ` - + + "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAACVBMVEW0PoluLy/BxeQTmwa1AAAAA3RSTlP////6yOLMAABAi0lEQVR42gGAQH+/AAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmzQoAQG7XFgAAAAASUVORK5CYII=", + } + } + style={ + [ + { + "borderRadius": 23, + "height": 46, + "width": 46, + }, + undefined, + ] + } + /> + + + + `; -exports[`Identicon should render correctly when useBlockieIcon is false 1`] = ` - - - + + + + + + + + + + + + + + + `; -exports[`Identicon should render correctly when useBlockieIcon is true 1`] = ` - - - + + + + + `; diff --git a/app/components/UI/Identicon/index.test.tsx b/app/components/UI/Identicon/index.test.tsx index 97adeda1390..d4c3d619a83 100644 --- a/app/components/UI/Identicon/index.test.tsx +++ b/app/components/UI/Identicon/index.test.tsx @@ -1,77 +1,33 @@ import React from 'react'; -import { shallow } from 'enzyme'; -import { render } from '@testing-library/react-native'; import Identicon from './'; -import configureMockStore from 'redux-mock-store'; -import { Provider } from 'react-redux'; -import useTokenList from '../../../components/hooks/DisplayName/useTokenList'; +import renderWithProvider from '../../../util/test/renderWithProvider'; -jest.mock('../../../components/hooks/DisplayName/useTokenList'); +const ADDRESS_MOCK = '0x123'; +const URI_MOCK = 'https://example.com/image.png'; describe('Identicon', () => { - const mockStore = configureMockStore(); - const mockUseTokenList = jest.mocked(useTokenList).mockImplementation(() => [ - { - name: 'test', - symbol: 'test', - decimals: 123, - address: '0x123', - occurrences: 1, - aggregators: ['test'], - iconUrl: 'https://test', - }, - ]); - - it('should render correctly when provided address found in tokenList and iconUrl is available', () => { - const addressMock = '0x0439e60f02a8900a951603950d8d4527f400c3f1'; - mockUseTokenList.mockImplementation(() => [ - { - name: 'test', - symbol: 'test', - decimals: 123, - address: addressMock, - iconUrl: 'https://example.com/icon.png', - occurrences: 1, - aggregators: ['test'], + it('renders Blockie from address', () => { + const wrapper = renderWithProvider(, { + state: { + settings: { useBlockieIcon: true }, }, - ]); - - const initialState = { - settings: { useBlockieIcon: true }, - }; - const store = mockStore(initialState); + }); - const wrapper = render( - - - , - ); expect(wrapper).toMatchSnapshot(); }); - it('should render correctly when useBlockieIcon is true', () => { - const initialState = { - settings: { useBlockieIcon: true }, - }; - const store = mockStore(initialState); - const wrapper = shallow( - - - , - ); + it('renders Jazzicon', () => { + const wrapper = renderWithProvider(, { + state: { + settings: { useBlockieIcon: false }, + }, + }); + expect(wrapper).toMatchSnapshot(); }); - it('should render correctly when useBlockieIcon is false', () => { - const initialState = { - settings: { useBlockieIcon: false }, - }; - const store = mockStore(initialState); - const wrapper = shallow( - - - , - ); + it('renders custom URI', () => { + const wrapper = renderWithProvider(); expect(wrapper).toMatchSnapshot(); }); }); diff --git a/app/components/UI/Identicon/index.tsx b/app/components/UI/Identicon/index.tsx index 8daa81dbd6d..d4dfffd2d17 100644 --- a/app/components/UI/Identicon/index.tsx +++ b/app/components/UI/Identicon/index.tsx @@ -4,10 +4,9 @@ import { Image, ImageStyle, View } from 'react-native'; import { toDataUrl } from '../../../util/blockies'; import FadeIn from 'react-native-fade-in-image'; import Jazzicon from 'react-native-jazzicon'; -import { connect } from 'react-redux'; import { useTheme } from '../../../util/theme'; -import { useTokenListEntry } from '../../../components/hooks/DisplayName/useTokenListEntry'; -import { NameType } from '../../UI/Name/Name.types'; +import { RootState } from '../../../reducers'; +import { useSelector } from 'react-redux'; interface IdenticonProps { /** @@ -27,9 +26,10 @@ interface IdenticonProps { */ noFadeIn?: boolean; /** - * Show a BlockieIcon instead of JazzIcon + * URI of the image to render + * Overrides the address if also provided */ - useBlockieIcon?: boolean; + imageUri?: string; } /** @@ -42,17 +42,14 @@ const Identicon: React.FC = ({ address, customStyle, noFadeIn, - useBlockieIcon = true, + imageUri, }) => { const { colors } = useTheme(); - const tokenListIcon = useTokenListEntry( - address || '', - NameType.EthereumAddress, - )?.iconUrl; - if (!address) return null; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const useBlockieIcon = useSelector((state: RootState) => state.settings.useBlockieIcon) ?? true; - const uri = useBlockieIcon && toDataUrl(address); + if (!address && !imageUri) return null; const styleForBlockieAndTokenIcon = [ { @@ -63,17 +60,13 @@ const Identicon: React.FC = ({ customStyle, ]; - if (tokenListIcon) { - return ( - - ); - } - - const image = useBlockieIcon ? ( - + const image = imageUri ? ( + + ) : useBlockieIcon ? ( + ) : ( @@ -93,10 +86,4 @@ const Identicon: React.FC = ({ ); }; -// TODO: Replace "any" with type -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mapStateToProps = (state: any) => ({ - useBlockieIcon: state.settings.useBlockieIcon, -}); - -export default connect(mapStateToProps)(memo(Identicon)); +export default memo(Identicon); diff --git a/app/components/UI/Name/Name.stories.tsx b/app/components/UI/Name/Name.stories.tsx index ab80b5d52d1..b211d08dd26 100644 --- a/app/components/UI/Name/Name.stories.tsx +++ b/app/components/UI/Name/Name.stories.tsx @@ -6,14 +6,15 @@ import { configureStore } from '@reduxjs/toolkit'; import { default as NameComponent } from './Name'; import { NameProperties, NameType } from './Name.types'; import { mockNetworkState } from '../../../util/test/network'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; const backdropStyle = { backgroundColor: 'white', padding: 50 }; const UNKNOWN_ADDRESS = '0x2990079bcdEe240329a520d2444386FC119da21a'; const METAMASK_MAINNET_BRIDGE_ADDRESS = '0x0439e60F02a8900a951603950d8D4527f400C3f1'; const NFT_ADDRESS = '0x12345643338A158DeC2FbF411B71aeB188743'; -const SELECTED_CHAIN_ID = '0x1'; const SELECTED_ACCOUNT = '0x72b1FDb6443338A158DeC2FbF411B71aeB157A42'; +const VARIATION_MOCK = CHAIN_IDS.MAINNET; type Story = StoryObj; @@ -25,7 +26,7 @@ const storeMock = configureStore({ backgroundState: { NetworkController: { ...mockNetworkState({ - chainId: SELECTED_CHAIN_ID, + chainId: VARIATION_MOCK, id: 'sepolia', nickname: 'Sepolia', ticker: 'ETH', @@ -38,7 +39,7 @@ const storeMock = configureStore({ allNfts: {}, allNftContracts: { [SELECTED_ACCOUNT]: { - [SELECTED_CHAIN_ID]: [ + [VARIATION_MOCK]: [ { address: NFT_ADDRESS, name: 'MyToken', @@ -67,13 +68,18 @@ const meta: Meta = { export default meta; export const UnknownAddress: Story = { - args: { type: NameType.EthereumAddress, value: UNKNOWN_ADDRESS }, + args: { + type: NameType.EthereumAddress, + value: UNKNOWN_ADDRESS, + variation: VARIATION_MOCK, + }, }; export const RecognizedFirstPartyContract: Story = { args: { type: NameType.EthereumAddress, value: METAMASK_MAINNET_BRIDGE_ADDRESS, + variation: VARIATION_MOCK, }, }; @@ -81,6 +87,7 @@ export const RecognizedNFT: Story = { args: { type: NameType.EthereumAddress, value: NFT_ADDRESS, + variation: VARIATION_MOCK, }, }; @@ -91,6 +98,7 @@ export const NarrowWidth: Story = { ); diff --git a/app/components/UI/Name/Name.test.tsx b/app/components/UI/Name/Name.test.tsx index fc0d764fc81..504a4b44dc4 100644 --- a/app/components/UI/Name/Name.test.tsx +++ b/app/components/UI/Name/Name.test.tsx @@ -7,6 +7,7 @@ import { NameType } from './Name.types'; import useDisplayName, { DisplayNameVariant, } from '../../hooks/DisplayName/useDisplayName'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; jest.mock('../../hooks/DisplayName/useDisplayName', () => ({ __esModule: true, @@ -49,6 +50,7 @@ describe('Name', () => { , ); @@ -72,6 +74,7 @@ describe('Name', () => { , ); diff --git a/app/components/UI/Name/Name.tsx b/app/components/UI/Name/Name.tsx index 5e44d36fe8f..17b01ea4656 100644 --- a/app/components/UI/Name/Name.tsx +++ b/app/components/UI/Name/Name.tsx @@ -48,20 +48,22 @@ const UnknownEthereumAddress: React.FC<{ address: string }> = ({ address }) => { }; const Name: React.FC = ({ - chainId, preferContractSymbol, type, value, + variation, }) => { if (type !== NameType.EthereumAddress) { throw new Error('Unsupported NameType: ' + type); } - const displayName = useDisplayName( + + const displayName = useDisplayName({ + preferContractSymbol, type, value, - chainId, - preferContractSymbol, - ); + variation, + }); + const { styles } = useStyles(styleSheet, { displayNameVariant: displayName.variant, }); @@ -72,7 +74,7 @@ const Name: React.FC = ({ return ( - + {displayName.name} diff --git a/app/components/UI/Name/Name.types.ts b/app/components/UI/Name/Name.types.ts index 45f7f241b6f..26cc8b12bff 100644 --- a/app/components/UI/Name/Name.types.ts +++ b/app/components/UI/Name/Name.types.ts @@ -1,5 +1,4 @@ import { ViewProps } from 'react-native'; -import { Hex } from '@metamask/utils'; /** * The name types supported by the NameController. @@ -12,8 +11,8 @@ export enum NameType { } export interface NameProperties extends ViewProps { - chainId?: Hex; preferContractSymbol?: boolean; type: NameType; value: string; + variation: string; } diff --git a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx index 8830e10e79b..3399ed8b0d6 100644 --- a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx +++ b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx @@ -57,6 +57,9 @@ const NativeAssetPill: React.FC = () => { const AssetPill: React.FC = ({ asset }) => { const { styles } = useStyles(styleSheet, {}); + // TODO: Remove global network selector usage once simulations refactored. + const chainId = useSelector(selectChainId); + return ( {asset.type === AssetType.Native ? ( @@ -66,7 +69,8 @@ const AssetPill: React.FC = ({ asset }) => { preferContractSymbol testID="simulation-details-asset-pill-name" type={NameType.EthereumAddress} - value={asset.address as Hex} + value={asset.address} + variation={chainId} /> )} diff --git a/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts b/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts index 62df7937225..d0428af4b64 100644 --- a/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts +++ b/app/components/UI/SimulationDetails/useSimulationMetrics.test.ts @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { + CHAIN_IDS, SimulationData, SimulationErrorCode, } from '@metamask/transaction-controller'; @@ -22,10 +23,13 @@ import { useSimulationMetrics, } from './useSimulationMetrics'; import useLoadingTime from './useLoadingTime'; +import { selectChainId } from '../../../selectors/networkController'; jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), useDispatch: jest.fn(), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useSelector: (fn: any) => fn(), })); jest.mock('react', () => ({ @@ -38,6 +42,7 @@ jest.mock('./useLoadingTime'); jest.mock('../../hooks/DisplayName/useDisplayName'); jest.mock('../../../core/redux/slices/transactionMetrics'); jest.mock('../../../components/hooks/useMetrics'); +jest.mock('../../../selectors/networkController'); const TRANSACTION_ID_MOCK = 'testTransactionId'; const LOADING_TIME_MOCK = 0.123; @@ -51,7 +56,6 @@ const BALANCE_CHANGE_MOCK = { } as unknown as BalanceChange; const DISPLAY_NAME_UNKNOWN_MOCK = { - name: null, variant: DisplayNameVariant.Unknown, }; @@ -63,7 +67,6 @@ const DISPLAY_NAME_SAVED_MOCK = { describe('useSimulationMetrics', () => { const updateTransactionMetricsMock = jest.mocked(updateTransactionMetrics); - const useDispatchMock = jest.mocked(useDispatch); const useStateMock = jest.mocked(useState); const useEffectMock = jest.mocked(useEffect); @@ -71,6 +74,7 @@ describe('useSimulationMetrics', () => { const useLoadingTimeMock = jest.mocked(useLoadingTime); const useMetricsMock = jest.mocked(useMetrics); const setLoadingCompleteMock = jest.fn(); + const selectChainIdMock = jest.mocked(selectChainId); // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -131,6 +135,7 @@ describe('useSimulationMetrics', () => { // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any useMetricsMock.mockReturnValue({ trackEvent: trackEventMock } as any); + selectChainIdMock.mockReturnValue(CHAIN_IDS.MAINNET); }); describe('updates transaction simulation metrics', () => { diff --git a/app/components/UI/SimulationDetails/useSimulationMetrics.ts b/app/components/UI/SimulationDetails/useSimulationMetrics.ts index ddf2573ff19..7507542b459 100644 --- a/app/components/UI/SimulationDetails/useSimulationMetrics.ts +++ b/app/components/UI/SimulationDetails/useSimulationMetrics.ts @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { SimulationData, SimulationErrorCode, @@ -17,6 +17,7 @@ import { NameType } from '../../UI/Name/Name.types'; import useLoadingTime from './useLoadingTime'; import { calculateTotalFiat } from './FiatDisplay/FiatDisplay'; import { BalanceChange } from './types'; +import { selectChainId } from '../../../selectors/networkController'; export interface UseSimulationMetricsProps { balanceChanges: BalanceChange[]; @@ -49,6 +50,9 @@ export function useSimulationMetrics({ const { loadingTime, setLoadingComplete } = useLoadingTime(); const dispatch = useDispatch(); + // TODO: Remove global network selector usage once simulations refactored. + const chainId = useSelector(selectChainId); + if (!loading) { setLoadingComplete(); } @@ -58,6 +62,7 @@ export function useSimulationMetrics({ value: asset.address ?? '', type: NameType.EthereumAddress, preferContractSymbol: true, + variation: chainId, }), ); diff --git a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx index 9c5e09462fa..56c3cc749ae 100644 --- a/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx +++ b/app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx @@ -19,6 +19,7 @@ import styleSheet from './StakeInputView.styles'; import useStakingInputHandlers from '../../hooks/useStakingInput'; import InputDisplay from '../../components/InputDisplay'; import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics'; +import { withMetaMetrics } from '../../utils/metaMetrics/withMetaMetrics'; const StakeInputView = () => { const title = strings('stake.stake_eth'); @@ -55,15 +56,6 @@ const StakeInputView = () => { navigation.navigate('StakeModals', { screen: Routes.STAKING.MODALS.LEARN_MORE, }); - trackEvent( - createEventBuilder(MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED) - .addProperties({ - selected_provider: 'consensys', - text: 'Tooltip Question Mark Trigger', - location: 'Stake Input View', - }) - .build(), - ); }; const handleStakePress = useCallback(() => { @@ -153,13 +145,30 @@ const StakeInputView = () => { fiatAmount={fiatAmount} isEth={isEth} currentCurrency={currentCurrency} - handleCurrencySwitch={handleCurrencySwitch} + handleCurrencySwitch={withMetaMetrics(handleCurrencySwitch, { + event: MetaMetricsEvents.STAKE_INPUT_CURRENCY_SWITCH_CLICKED, + properties: { + selected_provider: 'consensys', + text: 'Currency Switch Trigger', + location: 'Stake Input View', + // We want to track the currency switching to. Not the current currency. + currency_type: isEth ? 'fiat' : 'native', + }, + })} currencyToggleValue={currencyToggleValue} /> diff --git a/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap b/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap index 0193ba5abe1..fb47e1bf1c1 100644 --- a/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap +++ b/app/components/UI/Stake/Views/StakeInputView/__snapshots__/StakeInputView.test.tsx.snap @@ -567,7 +567,7 @@ exports[`StakeInputView render matches snapshot 1`] = ` onPress={[Function]} > { const title = strings('stake.unstake_eth'); @@ -68,14 +69,21 @@ const UnstakeInputView = () => { }); trackEvent( createEventBuilder(MetaMetricsEvents.REVIEW_UNSTAKE_BUTTON_CLICKED) - .addProperties({ - selected_provider: 'consensys', - tokens_to_stake_native_value: amountEth, - tokens_to_stake_usd_value: fiatAmount, - }) - .build(), + .addProperties({ + selected_provider: 'consensys', + tokens_to_stake_native_value: amountEth, + tokens_to_stake_usd_value: fiatAmount, + }) + .build(), ); - }, [amountEth, amountWei, createEventBuilder, fiatAmount, navigation, trackEvent]); + }, [ + amountEth, + amountWei, + createEventBuilder, + fiatAmount, + navigation, + trackEvent, + ]); return ( @@ -88,7 +96,16 @@ const UnstakeInputView = () => { fiatAmount={fiatAmount} isEth={isEth} currentCurrency={currentCurrency} - handleCurrencySwitch={handleCurrencySwitch} + handleCurrencySwitch={withMetaMetrics(handleCurrencySwitch, { + event: MetaMetricsEvents.UNSTAKE_INPUT_CURRENCY_SWITCH_CLICKED, + properties: { + selected_provider: 'consensys', + text: 'Currency Switch Trigger', + location: 'Unstake Input View', + // We want to track the currency switching to. Not the current currency. + currency_type: isEth ? 'fiat' : 'native', + }, + })} currencyToggleValue={currencyToggleValue} /> diff --git a/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx b/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx index 7c2b306cef3..92cc7b63ba3 100644 --- a/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx +++ b/app/components/UI/Stake/components/EstimatedAnnualRewardsCard.tsx @@ -69,7 +69,7 @@ const EstimatedAnnualRewardsCard = ({ > diff --git a/app/components/UI/Stake/components/LearnMoreModal/index.tsx b/app/components/UI/Stake/components/LearnMoreModal/index.tsx index b33f5aeba49..eb321f8d238 100644 --- a/app/components/UI/Stake/components/LearnMoreModal/index.tsx +++ b/app/components/UI/Stake/components/LearnMoreModal/index.tsx @@ -17,7 +17,8 @@ import { useNavigation } from '@react-navigation/native'; import { strings } from '../../../../../../locales/i18n'; import { POOLED_STAKING_FAQ_URL } from '../../constants'; import createLearnMoreModalStyles from './LearnMoreModal.styles'; -import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics'; +import { MetaMetricsEvents } from '../../../../hooks/useMetrics'; +import { withMetaMetrics } from '../../utils/metaMetrics/withMetaMetrics'; const styles = createLearnMoreModalStyles(); @@ -42,12 +43,21 @@ const LearnMoreModal = () => { const sheetRef = useRef(null); const navigation = useNavigation(); - const { trackEvent, createEventBuilder } = useMetrics(); const handleClose = () => { sheetRef.current?.onCloseBottomSheet(); }; + const handleLearnMoreBrowserRedirect = () => { + // Take to the faq page + navigation.navigate('Webview', { + screen: 'SimpleWebview', + params: { + url: POOLED_STAKING_FAQ_URL, + }, + }); + }; + return ( @@ -86,23 +96,14 @@ const LearnMoreModal = () => {