- TypeScript 95.3%
- JavaScript 3.9%
- Shell 0.5%
- HTML 0.2%
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
> Removes `toMatchSnapshot()` usage from `MainNavigator`, `Main`,
`Root`, and `RewardsController` tests, replacing snapshots with simpler
smoke assertions (`toBeTruthy()`) or explicit `toEqual(...)` state
expectations.
>
> Deletes the now-unused snapshot files under
`app/components/Nav/Main/__snapshots__`,
`app/components/Views/Root/__snapshots__`, and
`app/core/Engine/controllers/rewards-controller/__snapshots__`.
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk because changes are limited to test assertions and removal of
snapshot files; no production code paths are modified.
>
> **Overview**
> Removes Jest snapshot-based coverage for `MainNavigator`, `Main`,
`Root`, and `RewardsController` tests, replacing it with more focused
assertions (e.g., tab bar returns `null` vs rendered, presence of key
navigation screens/components, and explicit `deriveStateFromMetadata`
`toEqual` expectations).
>
> Deletes the corresponding snapshot files under
`app/components/Nav/Main/__snapshots__`,
`app/components/Views/Root/__snapshots__`, and
`app/core/Engine/controllers/rewards-controller/__snapshots__`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
|
||
|---|---|---|
| .agents/skills | ||
| .ai-pr-analyzer | ||
| .bundle | ||
| .claude | ||
| .cursor | ||
| .github | ||
| .husky | ||
| .storybook | ||
| .vscode | ||
| .yarn | ||
| android | ||
| app | ||
| certs | ||
| docs | ||
| ios | ||
| locales | ||
| patches | ||
| scripts | ||
| sourcemaps | ||
| tests | ||
| wdio | ||
| .android.env.example | ||
| .buckconfig | ||
| .depcheckrc.yml | ||
| .detoxrc.js | ||
| .e2e.env.example | ||
| .editorconfig | ||
| .eslintignore | ||
| .eslintrc.js | ||
| .git-blame-ignore-revs | ||
| .gitattributes | ||
| .gitignore | ||
| .gitmodules | ||
| .ios.env.example | ||
| .js.env.example | ||
| .nvmrc | ||
| .prettierignore | ||
| .prettierrc.js | ||
| .ruby-version | ||
| .watchmanconfig | ||
| .yarnrc.yml | ||
| AGENTS.md | ||
| app.config.js | ||
| architecture.svg | ||
| attribution.txt | ||
| babel.config.js | ||
| babel.config.tests.js | ||
| bitrise.yml | ||
| branch.json | ||
| builds.yml | ||
| ccache.conf | ||
| CHANGELOG.md | ||
| codecov.yml | ||
| coverage-thresholds.json | ||
| crowdin.yml | ||
| fingerprint.config.js | ||
| firebase.json | ||
| image.png | ||
| index.js | ||
| jest.config.js | ||
| jest.config.view.js | ||
| junitProperties.js | ||
| LICENSE | ||
| logo.png | ||
| metro.config.js | ||
| metro.transform.js | ||
| ota.config.js | ||
| package.json | ||
| react-native.config.js | ||
| ReactotronConfig.js | ||
| README.md | ||
| sentry.debug.properties.example | ||
| sentry.properties | ||
| sentry.release.properties.example | ||
| shim.js | ||
| shimPerf.js | ||
| sonar-project.properties | ||
| tailwind.config.js | ||
| tsconfig.json | ||
| tsdoc.json | ||
| wdyr.js | ||
| yarn.lock | ||
MetaMask Mobile
MetaMask is a mobile wallet that provides easy access to websites that use the Ethereum blockchain.
For up to the minute news, follow our Twitter or Medium pages.
To learn how to develop MetaMask-compatible applications, visit our Developer Docs.
To learn how to contribute to the MetaMask codebase, visit our Contributor Docs.
Documentation
- Architecture
- Expo Development Environment Setup
- Native Development Environment Setup
- Build Troubleshooting
- Component View Testing
- E2E Testing
- On-Ramp Provider Manual Testing
- Debugging
- Development Process
- Performance
- Release Build Profiling
- Storybook
- Miscellaneous
- Reassure Performance Testing (pilot)
Getting started
Infura Project Setup
MetaMask Mobile requires an Infura project ID to connect to blockchain networks.
Internal Contributors
- Grab the
.js.envfile from 1Password, ask around for the correct vault. This file contains theMM_INFURA_PROJECT_ID.
External Contributors
- Go to https://developer.metamask.io and create an account
- Generate an API key
- Add API key to
MM_INFURA_PROJECT_IDin.js.env.example - Rename
.js.env.exampleto.js.env - Rebuild the app
[!CAUTION]
Without an Infura project ID, the app cannot connect to blockchain networks.
Using Expo (recommended)
Expo is the fastest way to start developing. With the Expo framework, developers don't need to compile the native side of the application as before, hence no need for any native environment setup, developers only need to download a precompiled development build and run the javascript bundler. The development build will then connect with the bundler to load the javascript code.
Expo Environment Setup
Install node, yarn v4 and watchman.
Clone the project
git clone git@github.com:MetaMask/metamask-mobile.git && \
cd metamask-mobile
Install dependencies
yarn setup:expo
Run the bundler
yarn watch
Download and install the development build
-
Expo development builds are hosted in Runway buckets and are made available to all contributors through the public bucket links below. A new build is generated every time a PR is merged into the
mainbranch. -
For Android:
- Download and install an
.apkfile from this Runway bucket onto your Android device or emulator.
- Download and install an
-
For iOS:
- Physical device
- Your test device needs to first be registered with our Apple developer account.
- Once registered, download and install an
.ipafile from this Runway bucket onto your device.
- Simulator
- Download and install an
.appfile from this Runway bucket onto your simulator. - Note: Our
.appfiles are zipped and hosted underAdditional Artifactsin the bucket. Since this hosting additional artifacts in public buckets is a relatively new feature, contributors may find that some builds are missing additional artifacts. Under the hood, these are usually associated with failed or aborted Bitrise builds. We are working with the Runway team to better filter out these builds and are subject to change in the future.
- Download and install an
- Physical device
Load the app
If on a simulator:
- use the initial expo screen that appears when starting the development to choose the bundler url
- OR press "a" for Android or "i" for iOS on the terminal where the bundler is running
If on a physical device:
- Use the camera app to scan the QR code presented by the bundler running on the terminal
That's it! This will work for any javascript development, if you need to develop or modify native code please see the next section.
Native Development
If developing or modifying native code or installing any library that introduces or uses native code, it is not possible to use an Expo precompiled development build as you need to compile the native side of the application again. To do so, please follow the steps stated in this section.
Native Environment setup
Before running the app for native development, make sure your development environment has all the required tools. Several of these tools (ie Node and Ruby) may require specific versions in order to successfully build the app.
Setup your development environment
Building the app
Clone the project
git clone git@github.com:MetaMask/metamask-mobile.git && \
cd metamask-mobile
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.
Internal Contributor instructions
- Grab the
.js.envfile from 1Password, ask around for the correct vault. This file contains theGOOGLE_SERVICES_B64_ANDROIDandGOOGLE_SERVICES_B64_IOSsecrets that will be used to generate the relevant configuration files for IOS/Android. - Install and run & start the application as documented below.
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)
- 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(IMPORTANT).
- Add Configuration Files
- Create/Update the
google-services.jsonandGoogleService-Info.plistfiles in: android/app/google-services.json(for Android)ios/GoogleServices/GoogleService-Info.plistdirectory (for iOS)
- Create/Update the
- Create the correct base64 environments variables.
# 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
# Generate IOS Base64 Version of Google Services
export GOOGLE_SERVICES_B64_IOS="$(base64 -w0 -i ./ios/GoogleServices/GoogleService-Info.plist)" && echo "export GOOGLE_SERVICES_B64_IOS=\"$GOOGLE_SERVICES_B64_IOS\"" | tee -a .js.env
[!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
Install dependencies
yarn setup
Not the usual install command, this will run scripts and a lengthy postinstall flow
Running the app for native development
Run Metro bundler
yarn watch
Like a local server for the app
Run on a iOS device
yarn start:ios
Run on an Android device
yarn start:android
Development Tools
Git Hooks (Husky)
This project uses Husky to run pre-commit hooks that automatically format and lint your code before commits. The pre-commit hook runs lint-staged which executes:
- Prettier - Code formatting for
*.{js,jsx,ts,tsx,json,feature}files - ESLint - Linting and auto-fixing for
*.{js,jsx,ts,tsx}files
Disabling Husky Locally
If you need to disable Husky pre-commit hooks temporarily (e.g., for emergency commits or debugging), you have several options:
Option 1: Skip hooks for a single commit
git commit --no-verify -m "your commit message"
Option 2: Bypass hooks with environment variable
# Disable for current session
export HUSKY=0
git commit -m "your commit message"
# Or disable for a single command
HUSKY=0 git commit -m "your commit message"
Note: While these methods allow you to bypass the pre-commit hooks, remember that the CI/CD pipeline will still run linting checks. It's recommended to fix linting issues before pushing your changes to avoid build failures.