[pull] main from MetaMask:main#736
Merged
pull[bot] merged 33 commits intoReality2byte:mainfrom May 6, 2026
Merged
Conversation
- feat(perps): force unified account (#29492) ## **Description** HyperLiquid is deprecating DEX Abstraction mode (~May 9). This PR forces every Perps user onto **Unified Account** mode on app open and fixes the withdraw + balance-display flows that were broken in the target state. ### 1. Forced migration to Unified Account Migration paths by current abstraction mode: - `default` / `disabled` → silently migrated via `agentSetAbstraction({ abstraction: 'u' })` — no signing prompt - `dexAbstraction` → one-time EIP-712 prompt via `userSetAbstraction({ user, abstraction: 'unifiedAccount' })` — agent-key path is blocked by HL for this transition - `unifiedAccount` → no-op, cached immediately Key details: - Replaces deprecated `agentEnableDexAbstraction` / `userDexAbstraction` with `agentSetAbstraction` / `userSetAbstraction` / `userAbstraction` - Runs on perps section open (`#ensureReady()`) so users are set up before trading - `TradingReadinessCache` prevents repeated prompts (critical for hardware/QR wallets); `KEYRING_LOCKED` skips the cache so it retries on unlock - In-flight deduplication blocks concurrent signing attempts across provider instances - Segment analytics: `Perp Account Setup` event tracks mode distribution + outcome (`already_enabled` / `migration_required` / `success` / `failed`) ### 2. Withdraw + balance display fix (folded in from #29537) In Unified mode, USDC collateral lives in the spot clearinghouse, so `clearinghouseState.withdrawable` is $0 — pre-fix the withdraw screen showed $0 max with the button disabled, and the confirm-flow alert blocked submission. - `accountUtils.addSpotBalanceToAccountState` folds free spot USDC into `availableToTradeBalance` for Unified / Portfolio Margin; `dexAbstraction` / Standard keep spot separate (fold gated on resolved abstraction mode) - `HyperLiquidSubscriptionService.invalidateUserAbstractionCache(addr)` evicts stale pre-migration mode and re-aggregates immediately. Called by `HyperLiquidProvider` after both successful migration paths so the WS-driven aggregator doesn't serve a $0 balance for ~60s after migration completes. - Withdraw screen, withdraw validation, confirm-flow insufficient-balance alert, and percentage buttons all read `availableToTradeBalance ?? availableBalance` — fallback keeps Standard / legacy callers correct. ## **Changelog** CHANGELOG entry: Fixed Hyperliquid withdraw showing $0 and being blocked for users on Unified Account mode. ## **Related issues** Fixes: TAT-3112 (Unified Account migration), withdrawal break tracked in [TAT-3047](https://consensyssoftware.atlassian.net/browse/TAT-3047) ## **Manual testing steps** ```gherkin Feature: Unified Account migration + withdraw Scenario: First-time migration (default/disabled mode) Given the user has never used Perps When they open the Perps section Then migration runs silently (no prompt) And HIP-3 markets are visible Scenario: dexAbstraction → unifiedAccount migration Given the user has DEX Abstraction enabled When they open the Perps section Then a one-time EIP-712 signing prompt appears When they sign Then HIP-3 markets are visible and trades succeed And reopening Perps does not prompt again Scenario: Unified Account user withdraws spot-funded balance Given the user is in Unified Mode with $0 perps withdrawable and >$0 spot USDC When they open the Withdraw screen Then "Available Perps balance" shows the unified value (perps + free spot USDC) And Max enables and submission proceeds via withdraw3 And spot USDC drops by amount + fee ``` ### Live validation evidence Validated on dev1 mainnet (`0x8dc6…9003`) in the exact bug-class state: - HL mode: `unifiedAccount` / perps `withdrawable`: $0 / spot USDC free: $26.41 - App: `availableBalance` = $0 / `availableToTradeBalance` = $26.41 - Withdraw screen renders **"Available Perps balance: $26.41"** + Max enabled (pre-fix would show $0 / disabled) ## **Screenshots/Recordings** ### **Before** <!-- $0 max + disabled Max button on dev1 mainnet pre-fix --> ### **After** <!-- $26.41 max + Max enabled + successful withdraw on dev1 mainnet --> ## **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)). #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. [TAT-3047]: https://consensyssoftware.atlassian.net/browse/TAT-3047?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > High risk because it changes Perps account-mode migration/signing flow (including hardware-wallet behavior) and alters withdraw/payment balance calculations that gate user funds and transaction validation. > > **Overview** > Forces Perps users onto HyperLiquid **Unified Account** by replacing deprecated DEX-abstraction checks/calls with `userAbstraction` + `agentSetAbstraction`/`userSetAbstraction`, adding global in-flight/cached gating, retry semantics, and new `Perp Account Setup` analytics. > > Updates withdraw, confirmation, and pay-with flows to prefer `availableToTradeBalance ?? availableBalance`, and changes spot→perps folding to be **mode-gated** (fail-closed when abstraction mode is unknown) so Unified/Portfolio Margin users see spendable USDC while Standard/dexAbstraction users don’t over-report withdrawable funds. > > Renames cache-clearing APIs from DEX abstraction to Unified Account, adds hardware-wallet detection to defer user-sign prompts on browse, and expands tests/docs to cover unified-mode folding, migration paths, and race conditions in spot/account aggregation. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e5495f9. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: geositta <matthew.denton@consensys.net> Co-authored-by: Nick Gambino <nicholas.gambino@consensys.net> Co-authored-by: Arthur Breton <arthur.breton@consensys.net> Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com> [cc44460](cc44460) [TAT-3047]: https://consensyssoftware.atlassian.net/browse/TAT-3047?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description** Pre-emptively syncs `stable` (now containing the 7.75.0 release) into `release/7.75.1` so that PR #29674 (release/7.75.1 → stable) is conflict-free when ready to merge. ## **Changelog** CHANGELOG entry: N/A — release sync only ## **Related issues** - Unblocks #29674 ## **Resolution notes** - **Native version files** (`android/app/build.gradle`, `bitrise.yml`, `ios/MetaMask.xcodeproj/project.pbxproj`): kept release/7.75.1's values (`7.75.1` / `versionCode 4788`) — stable's `7.75.0` / `4784` is older and should not overwrite the release branch. - **CHANGELOG.md**: auto-merged cleanly. `[7.75.0]` and `[7.74.x]` sections from stable now appear in proper descending semver order alongside any `[Unreleased]` content from release/7.75.1. - **`tests/smoke/predict/predict-open-position.spec.ts`**: auto-merged; `describe.skip` preserved. ## **Manual testing steps** N/A — merge-only PR. ## **Pre-merge author checklist** - [x] Merge commit (not squash) so `release/7.75.1` history matches the standard release-sync workflow. Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: changes are limited to documentation/release notes and skipping a single smoke test, with no production code modifications. > > **Overview** > Merges in the `7.75.0` changelog entry (Added/Changed/Fixed lists) and updates the compare links so `[Unreleased]` now points to `v7.75.0...HEAD`. > > Temporarily disables the Predictions e2e smoke test by changing `describe` to `describe.skip` in `tests/smoke/predict/predict-open-position.spec.ts` (with a link to the tracking discussion). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ca1db7d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Co-authored-by: Cursor <cursoragent@cursor.com>
<!--
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**
Bump axios to 1.15.1
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **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 dependency bump limited to `axios` via Yarn
resolutions/lockfile, with potential for minor runtime behavior changes
in HTTP requests.
>
> **Overview**
> Updates the Yarn `resolutions` override to `axios@^1.15.1` and
refreshes `yarn.lock` to pull in `axios@1.15.2`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c6c6073. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29451) ## **Description** This PR removes legacy Predict Polymarket CLOB v1 support and completes the pUSD migration in Predict-owned code. It includes: - CLOB v2 as the unconditional Polymarket protocol path. - Removal of CLOB v1 protocol selection, order codec branches, and v1 Safe helper wrappers. - pUSD as the canonical Predict trading, fee, deposit, withdraw, reward-fee, and claim gas top-up token. - Legacy Safe USDC.e retained only as temporary hidden sweep state. - Legacy USDC.e → pUSD sweep preflight for deposit, withdraw, trade, and claim operations. - Displayed Predict balance as total recoverable Predict funds (`pUSD + legacy USDC.e`). - In-memory cache to stop refetching legacy USDC.e balance for a Safe after a zero balance is observed. Stack note: this PR is stacked on the confirmations-only pUSD PR so the diff stays limited to Predict-owned files. ## **Changelog** CHANGELOG entry: Updated Predict to use pUSD and the Polymarket CLOB v2 protocol. ## **Related issues** Fixes: [PRED-851](https://consensyssoftware.atlassian.net/browse/PRED-851) , [PRED-852](https://consensyssoftware.atlassian.net/browse/PRED-852) ## **Manual testing steps** ```gherkin Feature: Predict pUSD migration Scenario: user with pUSD places a Predict trade Given the user has a funded Predict Safe with pUSD When the user places a Predict trade Then the order is submitted through the CLOB v2 path And pUSD is used for trading and fee authorization Scenario: legacy user performs their first Predict operation Given the user has legacy USDC.e in their Predict Safe When the user deposits, withdraws, trades, or claims Then the Safe preflight wraps legacy USDC.e into pUSD before the main operation ``` ## **Screenshots/Recordings** ### **Before** N/A — code-only protocol migration PR; no screenshots captured. ### **After** N/A — code-only protocol migration PR; no screenshots captured. ## **Testing** - `yarn lint:tsc` - `yarn jest app/components/UI/Predict/providers/polymarket/protocol/definitions.test.ts app/components/UI/Predict/providers/polymarket/protocol/orderCodec.test.ts app/components/UI/Predict/providers/polymarket/protocol/transport.test.ts app/components/UI/Predict/providers/polymarket/preflight/v2AllowanceRequirements.test.ts app/components/UI/Predict/providers/polymarket/preflight/withdraw.test.ts app/components/UI/Predict/providers/polymarket/preflight/workflows.test.ts app/components/UI/Predict/providers/polymarket/PolymarketProvider.test.ts app/components/UI/Predict/controllers/PredictController.test.ts app/components/UI/Predict/hooks/usePredictBalanceTokenFilter.test.ts app/components/UI/Predict/hooks/usePredictRewards.test.ts app/components/UI/Predict/views/PredictBuyWithAnyToken/components/PredictPayWithRow/PredictPayWithRow.test.tsx --runInBand --forceExit` ## **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. #### 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** - [ ] 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] > **Medium Risk** > Updates on-chain token identifiers/addresses used for Predict gas fee and rewards calculations, which could impact transactions if misconfigured. Changes are localized to Predict hooks/controller and accompanying tests. > > **Overview** > Predict now consistently references the **pUSD / CLOB v2 collateral** across Predict-owned code: `PredictController` uses `MATIC_CONTRACTS_V2.collateral` as the `gasFeeToken` for claim/withdraw `addTransactionBatch`, `usePredictBalanceTokenFilter` displays the Predict balance row using the `POLYGON_PUSD` token (icon + symbol), and `usePredictRewards` estimates points using `POLYGON_PUSD_CAIP_ASSET_ID`. > > Cleans up account-state handling by removing `hasAllowances` expectations/tests and updating `usePredictAccountState` docs to reflect the slimmer `AccountState` shape. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7dfda61. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [PRED-851]: https://consensyssoftware.atlassian.net/browse/PRED-851?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --------- Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
## **Description**
Removes the unused temporary ContractBox and ContractBoxBase components
from `app/component-library/components-temp/Contracts`.
The prior audit found no production imports, and a follow-up reference
search confirms no remaining references.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: temporary component cleanup
Scenario: ContractBox temp components are removed
Given the repository is on this branch
When searching for ContractBox and ContractBoxBase references
Then no app, test, or Storybook references are found
```
## **Screenshots/Recordings**
N/A. Code cleanup only.
### **Before**
N/A
### **After**
N/A
## **Validation**
- `rg -n
"ContractBox|ContractBoxBase|CONTRACT_BOX|components-temp/Contracts" app
tests .storybook --glob '!node_modules/**'` returned no matches.
- `yarn lint:tsc` was run and failed on existing unrelated type errors
in confirmations, SocialLeaderboard tests, bridge messenger types,
multichain assets rates messenger types, and test account utilities.
## **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).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
## **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.
<!--
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**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **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: null
## **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]
> **High Risk**
> High risk because it changes perps balance/withdraw validation and
introduces an automatic Unified Account migration flow that can trigger
signing/caching behavior and affect how collateral is computed from spot
+ perps balances.
>
> **Overview**
> **Fixes Unified Account perps withdrawals and balance display.**
Withdrawal UI/validation, confirmations, pay-with token selection, and
insufficient-balance alerts now prefer `availableToTradeBalance`
(falling back to `availableBalance`) so Unified Account users no longer
see `$0`/blocked withdrawals.
>
> **Adds Unified Account migration + spot-fold gating in the perps
provider stack.** `HyperLiquidProvider` replaces the deprecated
DEX-abstraction enablement with a cached/in-flight
`userAbstraction`-based migration to Unified Account (silent agent path
for `default/disabled`, user-signed path for `dexAbstraction`, deferred
on hardware wallets), and
`HyperLiquidSubscriptionService`/`addSpotBalanceToAccountState` now fold
spot USDC into `availableToTradeBalance` only when the resolved
abstraction mode indicates it’s valid.
>
> **Release plumbing + telemetry.** Bumps app version to `7.75.1`
(Android/Bitrise/Changelog), adds `PERPS_ACCOUNT_SETUP` event +
abstraction-mode properties/statuses, adds `formatPerpsBalance`, and
updates/expands tests around unified mode, cache clearing, and spot-fold
race conditions.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c0b1d1c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- 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** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Activity’s unified transaction list passes `selectedAddress` into `TransactionElement` and Redux token selectors keyed by account. Those paths previously used the **globally selected** internal account. After switching the Activity network filter from a non-EVM network (e.g. Bitcoin) back to **all popular networks**, the selected account could still be non-EVM while EVM transactions remained in the list. EVM sends were compared against a non-EVM address (wrong direction / “Received”), and token metadata was looked up under the wrong account key on each chain (“Not available”). This change passes the account group’s **EVM** address for EVM rows (`UnifiedTransactionsView`), re-decodes when `selectedAddress` changes (`TransactionElement`), and adds `selectTokensByChainIdAndWalletAddress` so token maps match the same wallet address used for decoding. ## **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: Fixed Activity showing incorrect Sent/Received labels and "Not available" amounts after switching from a non-EVM network filter back to all popular networks. ## **Related issues** Fixes: #28035 Refs: https://consensyssoftware.atlassian.net/browse/TMCU-602 ## **Manual testing steps** ```gherkin Feature: Activity unified list after network filter change Scenario: EVM sends stay correct after non-EVM filter then popular networks Given the user has confirmed token sends on an EVM network (e.g. Linea) And Activity Transactions tab is open with the network filter set to that EVM chain When the user switches the filter to a non-EVM network (e.g. Bitcoin) And the user switches the filter back to all popular networks Then top EVM transactions still show Sent (not Received) with token amounts and fiat where applicable (not "Not available") ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** see video on [this comment](#28035 (comment)) from #28035 ### **After** https://github.com/user-attachments/assets/6e44a38c-9830-4aa4-a08d-63439533e74c ## **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. --> - [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. #### 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] > **Medium Risk** > Changes how Activity derives the address used to classify EVM transactions and fetch per-chain token metadata, which can alter Sent/Received labeling and displayed amounts across the unified list. Risk is limited to UI/state selection logic and is covered by added selector tests. > > **Overview** > Fixes unified Activity rendering when a non-EVM account remains selected by ensuring EVM list rows use the account group’s **EVM address** for direction/decoding and token metadata. > > `UnifiedTransactionsView` now passes the account group EVM address into `TransactionElement`, `TransactionElement` re-decodes when `selectedAddress` changes, and token lookup is switched to a new selector `selectTokensByChainIdAndWalletAddress` (with tests) so token maps are keyed by the same explicit wallet address rather than the globally selected account. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7910a16. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
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**
Adds FIFA World Cup (`fifwc`) as a supported sports league in the
Predict feature, enabling users to browse and bet on World Cup match
markets with live game data.
**Changes:**
- Added `fifwc` to the `PredictSportsLeague` union type
- Registered `fifwc` in `SUPPORTED_SPORTS_LEAGUES` so World Cup markets
appear in the sports feed
- Added `fifwc` to `DRAW_CAPABLE_LEAGUES` since soccer matches can end
in draws
- Added slug config in `gameParser.ts` with:
- Pattern: `fifwc-{team1}-{team2}-{date}`
- Team order: `home-away`
- Tag slug: `fifa-world-cup`
This follows the existing pattern for adding new leagues as documented
in `sports.ts`.
## **Changelog**
CHANGELOG entry: Added FIFA World Cup support to live sports predictions
## **Related issues**
Fixes: N/A — feature enablement for FIFA World Cup 2026
## **Manual testing steps**
```gherkin
Feature: FIFA World Cup prediction markets
Scenario: user views World Cup markets in the sports feed
Given the user has the Predict feature enabled
And FIFA World Cup markets are available from the provider
When user navigates to the Predict tab
And user browses sports markets
Then World Cup match markets appear in the list
And each market displays home and away teams with logos and scores
Scenario: user places a prediction on a World Cup match
Given the user is viewing a FIFA World Cup match market
And the market status is "open"
When user selects an outcome (home win, draw, or away win)
And user enters a bet amount
And user confirms the prediction
Then the order is placed successfully
And the position appears in the user's positions list
```
## **Screenshots/Recordings**
### **Before**
N/A
### **After**
N/A
## **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.
#### 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**
- [ ] 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.
<!-- Generated with the help of the pr-description AI skill -->
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk: this only extends existing league allowlists and slug
parsing to recognize a new `fifwc` league, with minimal impact on
existing leagues unless upstream data unexpectedly matches the new
pattern/tag.
>
> **Overview**
> Enables FIFA World Cup games in the Predict live sports flow by adding
the `fifwc` league across the sports league type, the
supported/draw-capable league allowlists, and the game slug parsing
configuration.
>
> This allows events tagged as `fifa-world-cup` with slugs matching
`fifwc-{team1}-{team2}-{date}` to be recognized and parsed like other
soccer leagues.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4db00e5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## **Description** This change updates the DeFi empty-state `Explore DeFi` CTA behavior so it no longer opens the external MetaMask Portfolio explore tokens URL in the in-app browser. Instead, pressing the CTA now navigates users to the in-app Explore flow and opens the Explore **Sites** section (`TrendingView -> SitesFullView`), matching the requested product direction and avoiding the blank page issue. ## **Changelog** CHANGELOG entry: Fixed the DeFi empty-state Explore button to open the in-app Explore sites screen instead of an external portfolio page. ## **Related issues** Fixes: #29471 https://consensyssoftware.atlassian.net/browse/ASSETS-3133 ## **Manual testing steps** ```gherkin Feature: DeFi empty-state Explore CTA navigation Scenario: user opens Explore from empty DeFi tab Given the user is on the DeFi tab with no open positions When user taps the "Explore DeFi" button Then the app navigates to the Explore Sites screen And the app does not open portfolio.metamask.io/explore/tokens ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** https://www.loom.com/share/04b68f115a2c44a190bd7049b5ee323e https://www.loom.com/share/88e42d07ee06480a90abde1d4771add2 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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 - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-9cac285f-d4ce-4156-a35e-004942245eb2"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-9cac285f-d4ce-4156-a35e-004942245eb2"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Prithpal Sooriya <prithpal@example.com>
<!--
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**
This cleans up some unintentional text issues when displaying Ondo
assets in the Rewards tab. This makes the Rewards tab match how Ondo
assets are displayed elsewhere in the app.
## **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: null
## **Related issues**
Fixes: n/a
## **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**
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-05-06 at 15 10 33"
src="https://github.com/user-attachments/assets/6b266c71-e1db-4e72-a30c-d8bcaab36fee"
/>
<!-- [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.
-->
- [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.
#### Performance checks (if applicable)
- [x] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [x] 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
- [x] 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`.
-->
- [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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk UI/text-only changes in Rewards Ondo views plus removal of a
now-unused formatting helper; primary risk is minor regressions in how
token names/units are displayed and in i18n key usage.
>
> **Overview**
> Rewards Ondo screens now **preserve backend-provided token display
names** (including the `(Ondo Tokenized)` suffix) instead of
stripping/truncating branding via `sanitizeOndoTokenName`, and
navigation to swaps passes the same unmodified name.
>
> Ondo portfolio rows adjust layout to truncate long names and change
the units subtext from a localized `"{{units}} shares"` string to a
direct `${units} ${TOKEN_SYMBOL}` format (uppercased), removing the
`position_units` i18n key and associated tests.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
60550e0. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- 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** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This updates the direct MetaMask design system dependencies used by mobile to the latest published releases: - `@metamask/design-system-react-native`: `^0.22.0` -> `^0.23.0` - `@metamask/design-tokens`: `^8.3.0` -> `^8.4.0` - `@metamask/design-system-twrnc-preset` remains at `^0.4.2` because it is already current I reviewed the upstream changelog and migration docs before upgrading. The main breaking change in the new React Native package is the `Toast` static API redesign, plus `Input` readonly naming alignment and shared `AvatarGroup` contract updates. No mobile code changes were required in this branch because the app does not directly consume those changed design-system APIs today. Release notes and migration references: - MMDS releases: https://github.com/MetaMask/metamask-design-system/releases - React Native 0.23.0 notes: https://github.com/MetaMask/metamask-design-system/releases/tag/v38.0.0 - React Native changelog: https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/CHANGELOG.md#0230 - React Native migration guide: https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/MIGRATION.md#from-version-0220-to-0230 - Design tokens changelog: https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-tokens/CHANGELOG.md#840 - Design tokens migration guide: https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-tokens/MIGRATION.md ## **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: null ## **Related issues** No issue: dependency maintenance upgrade for the latest MetaMask design system releases. ## **Manual testing steps** N/A ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A ### **After** N/A ## **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. --> - [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. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk dependency-only change, but it may introduce subtle UI/behavior differences if any screens consume updated design-system components indirectly. > > **Overview** > Upgrades design-system dependencies used by the app: `@metamask/design-system-react-native` to `^0.23.0` and `@metamask/design-tokens` to `^8.4.0`. > > Updates `yarn.lock` accordingly, including bumping transitive `@metamask/design-system-shared` to `^0.16.0`, with no app code changes beyond dependency versions. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 03812e9. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This PR syncs the stable branch to main for version 7.75.1. *Synchronization Process:* - Fetches the latest changes from the remote repository - Resets the branch to match the stable branch - Attempts to merge changes from main into the branch - Handles merge conflicts if they occur *File Preservation:* Preserves specific files from the stable branch: - CHANGELOG.md - bitrise.yml - android/app/build.gradle - ios/MetaMask.xcodeproj/project.pbxproj - package.json Indicates the next version candidate of main to 7.75.1
…9298) <!-- 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** Phase 2 cleanup of the Runway workflow split. Removes the legacy per-platform Runway entry workflows now that Runway has been flipped to dispatch the combined OTA-only and build-only workflows introduced in phase 1, and `release/7.73.x` / `release/7.74.x` are no longer actively maintained. ### Context Phase 1 (previous PR) added 5 new workflow files without touching anything existing: - `runway-ota-resolve-context.yml` - `runway-production-builds.yml` - `runway-rc-builds.yml` - `runway-ota-production.yml` - `runway-ota-rc.yml` That PR intentionally deferred the cleanup so Runway could keep dispatching the old per-platform workflow names against `release/7.73.x` and `release/7.74.x` (which cannot receive cherry-picks). ### What this PR does - **Deletes** the 4 legacy per-platform Runway entry workflows: - `runway-ios-production-workflow.yml` - `runway-android-production-workflow.yml` - `runway-ios-rc-workflow.yml` - `runway-android-rc-workflow.yml` - **Renames** `runway-ota-build-core.yml` → `auto-rc-ota-build-core.yml` to reflect that its only remaining caller is `build-rc-auto.yml` (auto-RC on push), not Runway. - **Refactors** the renamed core to call the reusable `runway-ota-resolve-context.yml` from phase 1 instead of keeping the `decide` + `resolve-pr` logic inline. Behaviour is identical; the logic is now shared with the OTA-only Runway workflows. - **Updates** `build-rc-auto.yml` `uses:` paths (two call sites) and the header comment to point at the renamed core. ### What this PR does NOT change - No behaviour change for `build-rc-auto.yml` — same OTA-vs-build auto-detection, same parallel platform dispatch, same Slack notification. - No behaviour change for the 4 phase-1 Runway workflows. ### Precondition for merge Before merging this PR, verify that: 1. Runway has been reconfigured to dispatch the 4 new workflow names (`runway-production-builds.yml`, `runway-rc-builds.yml`, `runway-ota-production.yml`, `runway-ota-rc.yml`). 2. `release/7.73.x` and `release/7.74.x` are no longer being hotfixed via Runway dispatch (they can still receive direct pushes — `build-rc-auto.yml` on those branches uses the files present on that ref, which still include the legacy core until those branches are fully retired). ## **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: null ## **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. --> - [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. #### 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`. --> - [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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Moderate risk because it changes GitHub Actions workflow entry points and reusable workflow wiring for OTA-vs-build detection, which could break release/RC automation if references or outputs diverge. > > **Overview** > Refactors the auto-RC release flow by replacing the legacy reusable `runway-ota-build-core.yml` with a new `auto-rc-ota-build-core.yml` that delegates OTA bump/PR resolution to `runway-ota-resolve-context.yml`, while keeping the same OTA-vs-build branching behavior. > > Cleans up CI by deleting the four per-platform Runway `workflow_dispatch` entry workflows (iOS/Android, RC/production) and updating `build-rc-auto.yml` to call the renamed core workflow for both iOS and Android RC triggers. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 54fc5ee. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ar (#29645) ## **Description** Bundle of polish items on the Money Home screen. - **MUSD-741** migrates the "X% APY" pill in the Money Home header from a hand-rolled `Box + Text` to the MMDS `Tag` component (severity = success), and bumps the inner text from `BodySm` (14px) to `BodyMd` (16px) so yield reads as a primary value prop. - **MUSD-743** removes the back chevron from the Money Home header. With Money now a top-level tab destination, the back button was misleading; the kebab on the right naturally aligns with the title via `HeaderStandard`'s built-in layout. - **MUSD-744** renders the global wallet action bar at the bottom of Money Home so the screen functions as a proper tab destination instead of a dead-end. Concretely: - The Money `Tab.Screen` is registered as `Routes.MONEY.ROOT` (instead of `Routes.MONEY.HOME`) and wired to `MoneyScreenStack`. This matches the existing `TabBar` handler which navigates to `Routes.MONEY.ROOT, { screen: Routes.MONEY.HOME }` — so the tab mounts with its inner stack and the global tab bar stays visible. - The outer `Stack.Screen` for `Routes.MONEY.ROOT` (which was pushing above `HomeTabs` and hiding the tab bar) is removed from `MainNavigator`. - All changes are inside `app/components/Nav/Main/MainNavigator.js` — no design-system-owned files are touched. - `MoneyFooter` ("Add money" CTA) was unpinned from its sticky-bottom position and now flows inside the `ScrollView` content as a normal section (`px-4 py-3`), with a single Divider above it (matching the section rhythm) and `paddingBottom: 40` on the scroll content. MUSD-747 will reintroduce sticky behaviour with peek-and-hide based on the onboarding stepper's viewport state. No analytics changes, no copy changes, no behavioural changes outside the navigation rewiring described above. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: - https://consensyssoftware.atlassian.net/browse/MUSD-741 - https://consensyssoftware.atlassian.net/browse/MUSD-743 - https://consensyssoftware.atlassian.net/browse/MUSD-744 ## **Manual testing steps** ```gherkin Feature: Money Home header polish + tab bar visibility Scenario: user opens Money Home via the bottom tab Given the Money Account feature flag is enabled When the user taps the Money tab in the bottom navigation Then Money Home renders with the global tab bar visible at the bottom And the "Money" tab is shown as active And no back chevron is rendered in the Money Home header And the options (kebab) icon sits in the top-right And the "X% APY" pill is rendered as an MMDS Tag at 16px text Scenario: Add money button placement Given Money Home is open When the user scrolls to the bottom of the page Then the "Add money" button renders inside the scroll content as the last section And it is preceded by the standard section divider And it has visible breathing room before the global tab bar ``` ## **Screenshots/Recordings** ### **Before** <!-- to be added --> ### **After** <!-- to be added --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Moderate risk due to navigation rewiring (Money tab now routes to `Routes.MONEY.ROOT`/`MoneyScreenStack` and a stack-level screen is removed), which could affect tab routing and back-stack behavior. UI/layout changes are otherwise straightforward and covered by updated tests. > > **Overview** > Makes Money a first-class bottom-tab destination by switching the conditional tab registration from `Routes.MONEY.HOME` to `Routes.MONEY.ROOT` and mounting `MoneyScreenStack` directly, while removing the extra `Routes.MONEY.ROOT` stack screen that previously sat above `HomeTabs` (keeping the global tab bar visible). > > Polishes Money Home UI: replaces the APY pill with the design-system `Tag`, updates the header to a title+menu-only `HeaderBase` (removing the back button), and simplifies the “Add money” footer from an animated/sticky overlay to a normal scroll section with fixed bottom padding; associated peek/hide stepper logic and its unit tests are deleted and component tests are updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a742e0d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Adds a new **Money balance card** to the wallet home screen, slotted
between the
wallet action bar (Buy/Swap/Send/Receive) and the Carousel/Tokens block.
The
card surfaces the user's Money Account balance, current vault APY, and a
direct CTA to add funds — replacing the chevron-style "Money" section
pattern
described in the Money Home Review (April 30, 2026) for users on the new
wallet home.
The card has two visual states sharing one component:
- **Empty** (MUSD-431) — balance `$0.00`, **Secondary** "Add" button.
- **Funded** (MUSD-752) — live `totalFiatFormatted` from
`useMoneyAccountBalance`,
**Secondary** "Add" button. Switches as soon as `totalFiatRaw > 0`.
Other behaviour:
- Tap card body → navigates to Money home (`Routes.MONEY.ROOT`)
- Tap "Add" → `Routes.MONEY.MODALS.ADD_MONEY_SHEET` (same flow as the
existing
Money home Add pill)
- Tap info icon → new `MoneyBalanceInfoSheet` modal (registered
alongside the
existing APY/Earnings info sheets)
- Skeleton placeholders while balance/APY are loading
- Render-gated by `selectMoneyHomeScreenEnabledFlag &&
isHomepageSectionsV1Enabled`
The legacy `MoneyAccountHomeRow` and `CashSection` are intentionally
untouched
in this PR — they continue to serve users without the Money home flag.
## **Changelog**
CHANGELOG entry: Added a new Money balance card to the wallet home
screen showing the user's Money Account balance, vault APY, and a quick
action to add funds.
## **Related issues**
Fixes: MUSD-431, MUSD-752
## **Manual testing steps**
```gherkin
Feature: Money balance card on wallet home
Scenario: user with no Money balance sees the empty state
Given the Money home feature flag is enabled
And the homepage sections v1 flag is enabled
And the user has no Money Account balance
When the user opens the wallet home screen
Then the Money balance card is visible between the action bar and the tokens
And the balance shows "$0.00"
And the "Add" button uses the Secondary variant
And the "4% APY" tag is visible
Scenario: user with a Money balance sees the funded state
Given the Money home feature flag is enabled
And the homepage sections v1 flag is enabled
And the user has a Money Account balance greater than $0.00
When the user opens the wallet home screen
Then the Money balance card shows the live USD balance
And the "Add" button uses the Secondary variant
Scenario: user taps the Money balance card body
Given the Money balance card is visible
When the user taps anywhere on the card outside of the Add button or info icon
Then the app navigates to the Money home screen
Scenario: user taps the info icon on the Money balance card
Given the Money balance card is visible
When the user taps the info icon next to "Money balance"
Then the Money balance info sheet opens
Scenario: feature flag is off
Given the Money home feature flag is disabled
When the user opens the wallet home screen
Then the Money balance card is not rendered
```
## **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
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
## **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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Adds new wallet-home UI and navigation paths (including a new modal
route) gated by feature flags; risk is mainly around routing/press
handlers and empty-state logic but is localized and well-covered by
tests.
>
> **Overview**
> Adds a new `MoneyBalanceCard` on the wallet home header area (shown
only when `selectMoneyHomeScreenEnabledFlag` is on) that displays Money
balance + APY with loading skeletons, and provides CTAs to open the Add
Money sheet, navigate to Money Home, or start the mUSD conversion
education flow for new users.
>
> Introduces a new `MoneyBalanceInfoSheet` bottom-sheet modal and
registers it in the Money modal stack via new route
`Routes.MONEY.MODALS.MONEY_BALANCE_INFO_SHEET`, along with new i18n
strings for the card label and sheet copy.
>
> Removes the legacy `MoneyAccountHomeRow` component/tests and updates
`CashSection` so the entire Cash section is not rendered when the Money
home flag is enabled; updates/extends unit tests (Wallet flag-gated
rendering, Cash section null behavior, Money modal registration)
accordingly.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
dea4013. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- 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** Four small UI/UX fixes for the What's Happening feature: 1. Home carousel card date visibility 2. Detail-view header size 3. Expanded card height consistency 4. in Tokens row the Buy button switched to Trade button, and now users should always be directed to Perps trade. When a token asset has an hlPerpsMarket entry the row now shows a Trade button navigating to Perps market details; otherwise it falls back to the existing Buy/Ramp flow. <img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-06 at 12 23 11" src="https://github.com/user-attachments/assets/d3a91506-e9d0-4182-a9ea-47732834268a" /> <img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-06 at 12 23 02" src="https://github.com/user-attachments/assets/2c40b688-b91b-4da5-9e10-d69bfc8b6844" /> <img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-06 at 12 01 23" src="https://github.com/user-attachments/assets/9b7371c3-4306-4794-be88-2671d0e01836" /> ## **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: null ## **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] > **Medium Risk** > Medium risk because it changes navigation behavior for token action buttons (routing some assets to Perps) and alters carousel/card layout rendering based on runtime measurement, which could affect visibility/scroll positioning across devices. > > **Overview** > Polishes What’s Happening UI by slightly increasing home carousel card heights, reducing card title lines to preserve footer/date visibility, and resizing the “View more” card to match. > > Updates the detail view header to a custom, smaller layout and makes the expanded-card carousel use a fixed measured `cardHeight`, gating card rendering and initial scroll positioning until layout is known; tests now simulate `onLayout` to validate rendering. > > Changes related-asset actions so token rows show **Trade** (navigating to Perps market details) when `hlPerpsMarket` is present, via new `useTradeNavigation`; `PerpsRow` is simplified to reuse the same hook, and `AssetRow` migrates to the design-system `Button` component. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7edb172. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
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**
- Replaces confirmed EVM Activity transactions with data from accounts
v4 API via React Query
- Adds infinite pagination for confirmed EVM history
- Keep local pending EVM transactions and existing non-EVM activity
unchanged
Note: Due to the API requesting a bearer token, there is a current
bottleneck in that token retrieval, in particular in
`AuthenticationController.getPrimaryEntropySourceId`
## **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: feat: use accounts API v4 for transactions
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Accounts API v4 Transactions
Scenario: user views EVM activity
Given the wallet has EVM confirmed on-chain activity
When user visits the Activity tab
Then confirmed onchain transactions returned by the Accounts v4 API is displayed on screen.
```
## **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]
> **Medium Risk**
> Moderate risk because it rewires the Activity/UnifiedTransactionsView
data source and filtering/deduping logic, which can change what
transactions appear and when pagination/refresh occurs.
>
> **Overview**
> **Confirmed EVM Activity now comes from the Accounts v4 API** via a
new React Query `useTransactionsQuery` hook, while local pending EVM
transactions continue to come from controller state and are
merged/deduped with the API results.
>
> Adds a small transformation layer (`helpers/adapters` +
`helpers/transformations`) to normalize API responses into
`TransactionMeta`-compatible view models, filter out unwanted items
(e.g. spam/incoming transfers/zero-value self-sends), and handle
bridge-history matching/deduping (including case-insensitive hash
matching).
>
> Updates `UnifiedTransactionsView` to support infinite scrolling
pagination (prefetch near the end of confirmed EVM items), show
initial/next-page loading indicators, and refresh both local polling and
the query. Related selector additions (`selectLocalTransactions`,
`selectRequiredTransactionHashes/Ids`) support filtering required child
txs and nonce/hash collisions, and tests/smoke mocks were updated
accordingly.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a3e6592. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Copilot <copilot@github.com>
<!--
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 the WDIO `generateTestId` helper and updates many UI
components to pass `testID` directly (dropping `Platform`-dependent
spreading) across buttons, toggles, list items, and modals.
>
> Introduces/standardizes colocated `*.testIds.ts` selector constants
for several screens/components (e.g., `Navbar`, `EthereumAddress`,
`AccountSelector`, `BrowserTab` options, `PhishingModal`,
`WebviewError`, `TermsAndConditions`, `ConnectQRHardware`) and updates
unit tests/components to import selectors from the new
`tests/selectors`/local testId modules instead of `wdio` paths.
>
## **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 refactor focused on test selectors: changes only how
`testID`s are assigned and referenced, with minimal runtime impact
beyond potential selector/name mismatches in tests/automation.
>
> **Overview**
> Removes the WDIO `generateTestId` utility and updates multiple UI
components to pass `testID` directly (dropping `Platform`-dependent
spreading) across buttons, toggles, list items, and modals.
>
> Introduces/standardizes co-located `*.testIds.ts` selector constants
(e.g., `Navbar`, `EthereumAddress`, `AccountSelector`, browser options,
phishing/webview error modals, terms, QR hardware connect) and updates
unit tests/components to import selectors from these modules (and from
`tests/selectors`) instead of `wdio` paths.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7d696af. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29548) ## **Description** Bundles six small Money Hub UX changes: - **MUSD-728** — Drop the inline **Learn more** CTA from `MoneyConvertStablecoins`. The Convert section ends after the feature tags / per-token rows; only the primary action remains. - **MUSD-729** — Money Hub balance heading reads **Your balance** (replacing the duplicate "Money" inline title; the page header still shows "Money"). Standalone "3% bonus" label removed from mUSD rows in the homepage token list — the row falls back to the standard percentage rail when there's no Convert CTA. - **MUSD-730** — `AssetOverviewClaimBonus` claim button switches from primary to **secondary** styling (no logic change). - **MUSD-731** — No code change required: the existing `MUSD_CONVERSION_APY` constant already drives every "3%" surface consistently. No outdated/conflicting variants remain. - **MUSD-732** — Five-item checklist (`Dollar-backed`, `No lockups`, `Daily bonus`, `MetaMask stablecoins`, `No MetaMask fee`) added to the **Get 3% on stablecoins** education splash with green checkmarks. - **MUSD-733** — Mounts the Convert section on the mUSD asset detail page via a new `AssetOverviewConvertSection` wrapper that reuses `MoneyConvertStablecoins`. The component already supports the three target states (no-mUSD informational, has-mUSD with stablecoins per-token rows, has-mUSD without stablecoins informational). The secondary claim CTA from MUSD-730 covers the claim-styling requirement. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [MUSD-728](https://consensyssoftware.atlassian.net/browse/MUSD-728), [MUSD-729](https://consensyssoftware.atlassian.net/browse/MUSD-729), [MUSD-730](https://consensyssoftware.atlassian.net/browse/MUSD-730), [MUSD-731](https://consensyssoftware.atlassian.net/browse/MUSD-731), [MUSD-732](https://consensyssoftware.atlassian.net/browse/MUSD-732), [MUSD-733](https://consensyssoftware.atlassian.net/browse/MUSD-733) ## **Manual testing steps** ```gherkin Feature: Money Hub polish Scenario: Money Hub Convert section (MUSD-728) Given I open the Money Hub Then the Convert to mUSD section ends after the feature tags or per-token rows And no "Learn more" button is rendered Scenario: Money Hub balance heading (MUSD-729) Given I open the Money Hub Then the balance section heading reads "Your balance" Scenario: mUSD token row label (MUSD-729) Given I view the wallet token list with mUSD on Mainnet/Linea Then the mUSD row no longer renders the green "3% bonus" label And the row falls back to the standard percentage rail when no Convert CTA applies Scenario: Asset detail claim button (MUSD-730) Given I open the mUSD asset detail page with a claimable bonus Then the "Claim" button uses secondary button styling Scenario: Education splash checklist (MUSD-732) Given I view the "Get 3% on stablecoins" education splash Then I see a checklist with: Dollar-backed, No lockups, Daily bonus, MetaMask stablecoins, No MetaMask fee And each item shows a green check icon Scenario: Asset detail Convert module (MUSD-733) Given I open the mUSD asset detail page And mUSD conversion is enabled and I am geo-eligible Then a Convert section renders below the claim card And it shows per-token rows for any eligible stablecoins, or the empty/info layout otherwise ``` ## **Screenshots/Recordings** <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/474cfcf1-d538-43c7-b798-4ca060fa1a88" /> <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/82ee004e-40c1-4972-bf93-f6ca44822150" /> <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/c7ae2bd0-cf04-4475-826a-806498a33a92" /> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. [MUSD-728]: https://consensyssoftware.atlassian.net/browse/MUSD-728?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Moderate risk: refactors conversion UI wiring and token list rendering paths (including a new compact mUSD layout and new analytics events/locations), which could affect navigation and tracking if misconfigured. > > **Overview** > **Money Hub UX polish for mUSD conversion and balances.** The Convert section (`MoneyConvertStablecoins`) is simplified by removing the inline *Learn more* CTA and now self-manages token fetching plus conversion initiation, emitting `MONEY_HUB_TOKEN_ROW_CONVERT_CLICKED` analytics with a passed-in `location`. > > **mUSD balance presentation is adjusted across Money surfaces.** `CashTokensFullView` adds a **"Your balance"** heading when Money Hub is enabled, introduces a new `MoneyMusdEmptyBalanceRow` for the zero-balance state, and passes a new `hideSecondaryPriceRow` flag through `Tokens`/`TokenList` to render a compact mUSD row without the price/percentage rail. Separately, mUSD token list items no longer show the standalone green `"3% bonus"` secondary label. > > **Other small UI/text tweaks.** `AssetOverviewClaimBonus` switches its CTA button to `Secondary` styling and removes the leading `+` from the estimated annual bonus display; the mUSD education screen is redesigned to use design-system components, adds a 5-item checklist, and removes the external “Terms apply” link while updating the education copy and i18n keys (cash → money, new checklist strings, new `money.your_balance`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6696fdc. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** This change replaces the temporary `HeaderCompactStandard` component with `HeaderStandard` from `@metamask/design-system-react-native` on Earn-related surfaces. **Reason:** Align Earn UI with the MetaMask design system and reduce reliance on `component-library/components-temp` for standard headers. **What changed:** `HeaderStandard` is used for the Lending “How it works” bottom sheet, the Earn input screen header (back button and end actions), and the Earn token list bottom sheet. Behavior is intended to match the previous header (title, back/close, analytics-related tests unchanged aside from naming). Unit test comments and a `describe` block name were updated to reference `HeaderStandard`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-699 ## **Manual testing steps** ```gherkin Feature: Earn headers use design system HeaderStandard Scenario: Earn input screen header matches prior behavior Given the user is on the Earn flow and opens the amount/input screen (e.g. stake or supply) When the user views the screen header and uses the back control Then the header shows the expected title and navigation behaves as before Scenario: Lending “How it works” modal Given the user opens the Lending learn-more / “How it works” bottom sheet from Earn When the user views the header and taps close Then the sheet dismisses as before Scenario: Earn token selection bottom sheet Given the user opens the token list bottom sheet (e.g. select token to supply or withdraw) When the user views the header title and uses the close control Then the sheet closes as before and titles match the prior copy for the flow ``` ## **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. #### 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** - [ ] 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 refactor that swaps a temporary header component for the design-system header on a few Earn screens; main regression risk is minor UI/interaction differences in back/close and end-icon rendering. > > **Overview** > Updates Earn surfaces to use the design-system `HeaderStandard` instead of the temporary `HeaderCompactStandard`, including the Lending “How it works” bottom sheet, the `EarnInputView` screen header (back + optional info icon), and the Earn token list bottom sheet (close button + title). > > Adjusts imports accordingly (including `IconName` usage from the design system) and updates unit test descriptions/comments to reference `HeaderStandard` while keeping behavioral assertions the same. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c517a2e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )