Skip to content

release: 7.75.1 #29674

Merged
chloeYue merged 15 commits into
stablefrom
release/7.75.1
May 6, 2026
Merged

release: 7.75.1 #29674
chloeYue merged 15 commits into
stablefrom
release/7.75.1

Conversation

@chloeYue
Copy link
Copy Markdown
Contributor

@chloeYue chloeYue commented May 4, 2026

Description

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

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

Before

After

Pre-merge author checklist

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 to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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.

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.

Reviewed by Cursor Bugbot for commit c0b1d1c. Bugbot is set up for automated code reviews on this repo. Configure here.

@chloeYue chloeYue requested review from a team as code owners May 4, 2026 16:53
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-qa QA team label May 4, 2026
@chloeYue chloeYue added auto-rc-builds enable automatic release candidate builds and removed team-qa QA team labels May 4, 2026
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 4, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

Comment thread .github/workflows/run-performance-e2e.yml
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.55405% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.27%. Comparing base (5078ae1) to head (2f18776).
⚠️ Report is 1528 commits behind head on stable.

Files with missing lines Patch % Lines
app/components/UI/FoxLoader/FoxLoader.tsx 92.59% 3 Missing and 3 partials ⚠️
...nts/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx 85.29% 3 Missing and 2 partials ⚠️
.../Views/MoneyHowItWorksView/MoneyHowItWorksView.tsx 83.33% 3 Missing and 1 partial ⚠️
...ents/UI/Carousel/StackCardEmpty/StackCardEmpty.tsx 88.00% 1 Missing and 2 partials ⚠️
...omponents/UI/Money/hooks/useMoneyAccountBalance.ts 92.50% 0 Missing and 3 partials ⚠️
app/components/UI/FoxLoader/FoxLoader.styles.ts 60.00% 0 Missing and 2 partials ⚠️
...onents/MoneyOnboardingCard/MoneyOnboardingCard.tsx 80.00% 0 Missing and 1 partial ⚠️
...etworkVerificationInfo/NetworkVerificationInfo.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           stable   #29674      +/-   ##
==========================================
+ Coverage   81.50%   82.27%   +0.76%     
==========================================
  Files        4621     5130     +509     
  Lines      121060   135930   +14870     
  Branches    26604    30605    +4001     
==========================================
+ Hits        98671   111831   +13160     
- Misses      15451    16469    +1018     
- Partials     6938     7630     +692     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- 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>
@github-actions

This comment has been minimized.

@chloeYue chloeYue added the auto-rc-builds enable automatic release candidate builds label May 5, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fe173db. Configure here.

Comment thread app/components/UI/Perps/hooks/useWithdrawValidation.ts
@runway-github runway-github Bot temporarily deployed to build-production May 5, 2026 10:48 Inactive
sleepytanya
sleepytanya previously approved these changes May 5, 2026
chloeYue and others added 2 commits May 5, 2026 19:10
Co-authored-by: Cursor <cursoragent@cursor.com>
@chloeYue chloeYue removed the auto-rc-builds enable automatic release candidate builds label May 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🚀 RC Builds Ready for Testing

Platform Link Version
iOS TestFlight Go to TestFlight and download build 4809
Android Download from CI RC 7.75.1 (4809) — download APK artifact from the linked run
More Info
  • Version: 7.75.1
  • iOS Build Number: 4809
  • Android Build Number: 4809
  • Build Pipeline: View Pipeline

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Teams Signed Off
53/100 6 4 36 0/0
Executive Summary

Release Focus: Migration from deprecated HyperLiquid DEX Abstraction to Unified Account mode, with balance reporting fixes ensuring Unified Account and Portfolio Margin users see correct withdrawable balances across all Perps flows.

Key Changes:

  • HyperLiquidProvider migrated from dexAbstraction to unifiedAccount mode with a kill-switch option (useUnifiedAccount flag) and retry logic for transient failures
  • New availableToTradeBalance field introduced across withdraw view, payment tokens, balance alerts, and confirmation screens to correctly report spendable balance for Unified Account users (previously showed $0)
  • HyperLiquidSubscriptionService now fetches userAbstraction mode alongside spot state and uses hyperLiquidModeFoldsSpot to gate whether spot balances fold into perps collateral
  • Hardware wallet detection added to HyperLiquidWalletService to identify Ledger/QR hardware accounts
  • formatPerpsBalance utility added to truncate displayed balances to 2 decimals, preventing users from attempting to withdraw more than the actual withdrawable amount

Critical Areas: Perps Withdraw flow with Unified Account mode users (balance display, max withdraw, validation), Account setup migration from dexAbstraction to unifiedAccount (EIP-712 signing prompt timing), Balance aggregation correctness when spot balances fold into perps collateral, Insufficient balance alert accuracy for Unified Account users, Payment token selection showing correct available balance in Pay-with sheet

Overall Risk: HIGH

Recommendation: Conditional go — the Unified Account migration touches every balance-reporting surface in the Perps feature and introduces new async retry logic with a kill-switch. All high-risk withdraw, balance display, and account setup scenarios must pass before release. The fail-closed design (under-reporting rather than over-reporting) is correct but must be verified to not block legitimate withdrawals for Unified Account users.

Release Scenarios (10)

High Risk Scenarios (6)

1. Perps - Withdraw Flow (Unified Account)

Risk Level: HIGH

Why This Matters: PerpsWithdrawView.tsx now uses account?.availableToTradeBalance ?? account?.availableBalance for both the max amount calculation and the balance check. useWithdrawValidation.ts and useInsufficientPerpsBalanceAlert.ts also switched to availableToTradeBalance. For Unified Account users, availableBalance was $0 (mirrors HL's clearinghouseState.withdrawable), so the old code would have shown $0 and blocked all withdrawals. The new code must correctly surface the folded balance.

Preconditions:

  • User has a HyperLiquid Perps account in Unified Account mode (unifiedAccount abstraction)
  • User has USDC spot balance on HyperLiquid that folds into perps collateral
  • User is on a supported network (Arbitrum mainnet)
  • App is fully initialized and subscription service has resolved userAbstraction mode

Test Steps:

  1. Open MetaMask Mobile and navigate to the Perps section - verify the account balance displayed reflects availableToTradeBalance (spot + perps collateral combined), NOT $0
  2. Tap the Withdraw button to open PerpsWithdrawView - verify the displayed available balance matches the combined spot+perps balance and is truncated to 2 decimal places
  3. Tap the 'Max' button - verify the max withdraw amount populates with the truncated availableToTradeBalance value, not availableBalance
  4. Enter a withdrawal amount equal to the full displayed balance - verify no insufficient balance error appears
  5. Enter a withdrawal amount $0.01 above the displayed balance - verify an insufficient balance alert is shown
  6. Enter a valid withdrawal amount (e.g., 50% of balance) - verify the confirmation screen shows the correct available balance using formatPerpsBalance (truncated to 2 decimals)
  7. Confirm the withdrawal - verify the EIP-712 signing prompt appears and the transaction proceeds
  8. After withdrawal completes, verify the updated balance reflects the deduction correctly

Expected Outcomes:

  • availableToTradeBalance is used as the primary balance source throughout the withdraw flow
  • Max withdraw amount matches the truncated availableToTradeBalance, not availableBalance
  • Insufficient balance validation uses availableToTradeBalance for comparison
  • Confirmation screen displays formatPerpsBalance output (truncated, never exceeds actual withdrawable)
  • Withdrawal transaction succeeds without signing prompt appearing during initial Perps view load

2. Perps - Account Setup Migration (dexAbstraction → unifiedAccount)

Risk Level: HIGH

Why This Matters: HyperLiquidProvider.ts completely replaced #ensureDexAbstractionEnabled with #ensureUnifiedAccountEnabled, introducing allowUserSigning gating and #unifiedAccountSetupNeedsRetry logic. The TradingReadinessCache renamed dexAbstraction to unifiedAccount throughout. A regression here could either spam users with signing prompts on every page load or silently fail to migrate, leaving users unable to trade.

Preconditions:

  • User has an existing HyperLiquid Perps account previously set up with dexAbstraction mode
  • User is using a software wallet (not hardware)
  • TradingReadinessCache has no prior unifiedAccount entry for this user/network
  • Network is Arbitrum mainnet

Test Steps:

  1. Open MetaMask Mobile and navigate to the Perps section - verify NO EIP-712 signing prompt appears during initial load (allowUserSigning=false at init time)
  2. Attempt to place a trade or initiate a withdrawal - verify an EIP-712 signing prompt appears for the unifiedAccount migration (allowUserSigning=true at action time)
  3. Approve the EIP-712 signing prompt - verify the migration completes and the trade/withdrawal proceeds
  4. Navigate away and return to Perps - verify NO second signing prompt appears (TradingReadinessCache records the successful migration)
  5. Force-close and reopen the app, navigate to Perps - verify the cached migration state persists and no re-signing is required
  6. Attempt a trade with the keyring locked (e.g., biometric auth dismissed) - verify the flow retries on next action rather than permanently failing
  7. Simulate a REST userAbstraction lookup failure by using airplane mode briefly during init - verify the retry flag is set and the next action-time entry retries the migration

Expected Outcomes:

  • No signing prompt during passive Perps browsing (init path with allowUserSigning=false)
  • Signing prompt appears exactly once when user first attempts to trade or withdraw after migration
  • Successful migration is cached and not repeated across sessions
  • Transient failures (locked keyring, REST outage) trigger retry on next user action, not permanent failure
  • Analytics event PERPS_ACCOUNT_SETUP fires with correct abstraction_mode and previous_abstraction_mode properties

3. Perps - Balance Display (Standard vs Unified Account)

Risk Level: HIGH

Why This Matters: hyperLiquidModeFoldsSpot in hyperliquid-types.ts and addSpotBalanceToAccountState in accountUtils.ts now gate spot folding on the resolved abstraction mode. HyperLiquidSubscriptionService.ts added #abstractionModeByUser map and setUserAbstractionMode. Multiple hooks (usePerpsBalanceTokenFilter, usePerpsPaymentTokens, useTransactionCustomAmount) all switched to availableToTradeBalance. Incorrect folding would either over-report funds (Standard users) or under-report (Unified users).

Preconditions:

  • Two test accounts available: one in Standard/dexAbstraction mode, one in Unified Account mode
  • Both accounts have USDC spot balance on HyperLiquid
  • Both accounts have open perps positions with margin

Test Steps:

  1. Log in with the Standard/dexAbstraction account and navigate to Perps - verify availableBalance is shown (spot balance does NOT fold into perps collateral display)
  2. Open the Pay-with sheet for a trade - verify the Perps balance shown matches availableBalance only, not spot+perps combined
  3. Switch to the Unified Account mode account and navigate to Perps - verify availableToTradeBalance is shown (spot balance DOES fold into perps collateral)
  4. Open the Pay-with sheet for a trade - verify the Perps balance shown matches the combined spot+perps value
  5. For the Unified Account user, verify the balance in the payment tokens list (usePerpsPaymentTokens) shows availableToTradeBalance
  6. For the Unified Account user, verify the balance filter (usePerpsBalanceTokenFilter) uses availableToTradeBalance for the Pay-with header
  7. Trigger a WebSocket spot snapshot update and verify balances re-aggregate correctly using the cached abstraction mode
  8. Verify that during the initial subscription window (before userAbstraction resolves), the balance fails closed (shows perps-only balance, not over-reported)

Expected Outcomes:

  • Standard mode users see perps-only balance (no spot folding)
  • Unified Account users see combined spot+perps balance via availableToTradeBalance
  • Fail-closed behavior during unresolved abstraction mode (hyperLiquidModeFoldsSpot returns false for null/undefined)
  • Balance updates correctly after WebSocket spot snapshots with setUserAbstractionMode called
  • No over-reporting of withdrawable funds for Standard/dexAbstraction users

4. Perps - Hardware Wallet Account Detection

Risk Level: HIGH

Why This Matters: HyperLiquidWalletService.ts added isSelectedHardwareWallet() using a hardcoded HARDWARE_KEYRING_TYPES set and AccountTreeController:getSelectedAccountGroup. This is new code with no prior equivalent — if metadata structure differs from expected or the messenger call fails, it could throw or silently return wrong values, affecting the migration flow for hardware wallet users.

Preconditions:

  • User has a Ledger hardware wallet connected to MetaMask Mobile
  • Hardware wallet account is selected as the active account
  • User navigates to the Perps section

Test Steps:

  1. Connect a Ledger hardware wallet and select the hardware account as active
  2. Navigate to the Perps section - verify isSelectedHardwareWallet() correctly identifies the account as hardware
  3. Attempt to initiate the unifiedAccount migration flow - verify the flow handles hardware wallet signing appropriately (no silent failure)
  4. Switch to a software wallet account and navigate to Perps - verify isSelectedHardwareWallet() returns false
  5. Attempt a trade with the software account - verify normal signing flow proceeds
  6. Switch back to hardware wallet and attempt a withdrawal - verify the hardware signing prompt appears correctly
  7. Test with a QR hardware wallet (if available) - verify HARDWARE_KEYRING_TYPES set includes 'QR Hardware Wallet Device' and detection works

Expected Outcomes:

  • isSelectedHardwareWallet() returns true for Ledger and QR hardware keyrings
  • isSelectedHardwareWallet() returns false for software accounts
  • Hardware wallet accounts are handled without crashes when metadata or keyring type is missing
  • The confirmations_pay_hardware feature flag being disabled does not break hardware wallet detection logic itself

5. Perps - Subscription Service Balance Aggregation

Risk Level: HIGH

Why This Matters: HyperLiquidSubscriptionService.ts changed #refreshSpotState to use Promise.allSettled for concurrent spot+abstraction fetching, added #abstractionModeByUser map, and modified the fingerprint string to include availableToTradeBalance. The generation-check bailout was also removed to ensure abstraction mode is always resolved. These are complex async changes where race conditions could cause stale or incorrect balance reporting.

Preconditions:

  • User has a Unified Account mode HyperLiquid account
  • Active WebSocket connection to HyperLiquid
  • User has both spot USDC and perps positions

Test Steps:

  1. Open Perps with a Unified Account user - verify the initial REST fetch of spotClearinghouseState and userAbstraction runs concurrently via Promise.allSettled
  2. Verify that if userAbstraction REST call fails (simulate network error), the spot state is still processed and balance is shown fail-closed (no fold)
  3. Verify that if spotClearinghouseState REST call fails but userAbstraction succeeds, the abstraction mode is still cached for future use
  4. After both calls succeed, verify setUserAbstractionMode is called and #aggregateAndNotifySubscribers re-runs with the correct fold setting
  5. Trigger a WebSocket spot update - verify the balance re-aggregates using the cached abstraction mode (not re-fetching REST)
  6. Verify the account state fingerprint now includes availableToTradeBalance in the change detection string
  7. Switch accounts mid-session - verify #abstractionModeByUser map correctly keys by lowercase address and the new account's mode is fetched fresh

Expected Outcomes:

  • Promise.allSettled ensures partial failures don't block the entire balance fetch
  • Abstraction mode is cached per-user (lowercase address key) and survives WebSocket reconnects
  • Balance change detection fires when availableToTradeBalance changes (new field in fingerprint string)
  • Account switch correctly fetches new user's abstraction mode
  • No stale abstraction mode from previous user bleeds into new user's balance calculation

6. Perps - Withdraw Confirmation Screen Balance

Risk Level: HIGH

Why This Matters: perps-withdraw-balance.tsx replaced the inline useMemo with formatPerpsBalance and switched to availableToTradeBalance. useInsufficientPerpsBalanceAlert.ts now reads availableToTradeBalance from PerpsController state. The new formatPerpsBalance utility in formatUtils.ts uses truncateToTwoDecimals to prevent displayed amount from exceeding actual withdrawable — a regression here could allow users to attempt withdrawals that will fail on-chain.

Preconditions:

  • User has a Unified Account mode HyperLiquid account with balance
  • User has initiated a withdrawal and reached the confirmation screen

Test Steps:

  1. Initiate a withdrawal from the Perps section to reach the confirmation screen
  2. Verify the 'Available Balance' label on the confirmation screen shows formatPerpsBalance output (truncated to 2 decimals, never exceeds actual withdrawable)
  3. Verify the balance shown uses availableToTradeBalance ?? availableBalance (not just availableBalance)
  4. For a Unified Account user with $50.389 balance, verify the display shows '$50.38' (truncated down, not rounded up to $50.39)
  5. For a Standard mode user, verify the balance shown uses availableBalance directly
  6. Verify the insufficient balance alert on the confirmation screen uses availableToTradeBalance from PerpsController state
  7. Attempt to confirm a withdrawal that exceeds the displayed balance - verify the alert fires correctly

Expected Outcomes:

  • Confirmation screen balance is truncated down (never over-reports withdrawable amount)
  • formatPerpsBalance utility correctly handles raw numeric strings, formatted strings, and numbers
  • Unified Account users see combined balance, Standard users see perps-only balance
  • Insufficient balance alert correctly compares against availableToTradeBalance

Medium Risk Scenarios (4)

1. Perps - Kill-Switch and Retry Resilience

Risk Level: MEDIUM

Why This Matters: HyperLiquidProvider.ts introduced #unifiedAccountSetupNeedsRetry and modified #ensureReady to reset the memoized promise when retry is needed. The kill-switch (useUnifiedAccount=false) is the emergency rollback path. These resilience mechanisms are critical for production stability but are complex async state machines that could have subtle bugs.

Preconditions:

  • Access to a debug/staging build where useUnifiedAccount can be set to false
  • User has a HyperLiquid account in dexAbstraction mode
  • Network connectivity can be toggled

Test Steps:

  1. With useUnifiedAccount=false (kill-switch active), navigate to Perps - verify no unifiedAccount migration is attempted and legacy flow is used
  2. Verify trades and withdrawals still work with the kill-switch enabled (legacy programmatic HIP-3 transfer path)
  3. Re-enable useUnifiedAccount=true and simulate a transient REST failure during #ensureUnifiedAccountEnabled - verify #unifiedAccountSetupNeedsRetry is set to true
  4. Verify that on the next action-time entry (trade/withdraw), the migration is retried rather than using the cached failed promise
  5. Simulate the scenario where two provider instances race to run #ensureUnifiedAccountEnabled - verify the post-wait cache check prevents double-migration
  6. Verify that a successful migration sets #unifiedAccountSetupNeedsRetry to false and the memoized promise is kept

Expected Outcomes:

  • Kill-switch (useUnifiedAccount=false) completely bypasses migration and uses legacy flow
  • Transient failures set retry flag and allow re-attempt on next user action
  • Concurrent provider instances don't double-migrate (post-wait cache check works)
  • Successful migration is memoized and not repeated

2. Perps - Analytics Events for Account Setup

Risk Level: MEDIUM

Why This Matters: eventNames.ts added ABSTRACTION_MODE, PREVIOUS_ABSTRACTION_MODE properties and ALREADY_ENABLED, MIGRATION_REQUIRED values. MetaMetrics.events.ts added PERPS_ACCOUNT_SETUP event. These are new analytics instrumentation points — incorrect firing could skew migration metrics used to assess rollout health.

Preconditions:

  • User has analytics/MetaMetrics enabled
  • User has a HyperLiquid account requiring unifiedAccount migration
  • Network is Arbitrum mainnet

Test Steps:

  1. Complete the unifiedAccount migration flow for a dexAbstraction account - verify PERPS_ACCOUNT_SETUP event fires
  2. Verify the event includes abstraction_mode property with value 'unifiedAccount'
  3. Verify the event includes previous_abstraction_mode property with the prior mode (e.g., 'dexAbstraction')
  4. For an account already in unifiedAccount mode, verify the event fires with ALREADY_ENABLED value
  5. For an account requiring migration, verify the event fires with MIGRATION_REQUIRED value
  6. Verify no duplicate events fire when the cached migration state is used on subsequent sessions

Expected Outcomes:

  • PERPS_ACCOUNT_SETUP event fires exactly once per migration
  • abstraction_mode and previous_abstraction_mode properties are correctly populated
  • ALREADY_ENABLED and MIGRATION_REQUIRED event values are used in the correct scenarios
  • No analytics events fire during passive browsing (init path)

3. Perps - Payment Token Selection with Unified Account Balance

Risk Level: MEDIUM

Why This Matters: usePerpsPaymentTokens.ts and usePerpsBalanceTokenFilter.ts both switched to availableToTradeBalance ?? availableBalance. useTransactionCustomAmount.ts also updated. For Unified Account users where availableBalance is $0, the old code would have shown $0 in the Pay-with sheet and potentially hidden the HyperLiquid payment option entirely, blocking trades.

Preconditions:

  • User has a Unified Account mode HyperLiquid account
  • User has USDC in both spot and perps positions
  • User navigates to place a trade and opens the Pay-with token selector

Test Steps:

  1. Open the Pay-with token selector for a Perps trade - verify the HyperLiquid balance entry shows availableToTradeBalance (combined spot+perps)
  2. Verify the balance shown in the Pay-with header matches availableToTradeBalance, not availableBalance
  3. For a Standard mode user, verify the Pay-with sheet shows availableBalance only
  4. Select the HyperLiquid balance as payment method - verify the percentage buttons (25%, 50%, 75%, 100%) calculate against availableToTradeBalance
  5. Tap 100% - verify the amount populated matches truncateToTwoDecimals(availableToTradeBalance)
  6. Verify the balance filter (usePerpsBalanceTokenFilter) correctly includes/excludes the HyperLiquid option based on availableToTradeBalance > 0

Expected Outcomes:

  • Pay-with sheet shows correct combined balance for Unified Account users
  • Percentage buttons calculate against availableToTradeBalance
  • Balance filter uses availableToTradeBalance for threshold checks
  • Standard mode users are not affected (fallback to availableBalance works correctly)

4. Perps - Portfolio Margin Mode Balance Handling

Risk Level: MEDIUM

Why This Matters: hyperliquid-types.ts defines hyperLiquidModeFoldsSpot to return true for both 'unifiedAccount' and 'portfolioMargin'. The HL_ABSTRACTION_WIRE constants document the full wire format. If portfolioMargin handling is broken, those users would see $0 available balance and be unable to trade or withdraw.

Preconditions:

  • User has a HyperLiquid account in portfolioMargin abstraction mode
  • User has USDC spot balance
  • Network is Arbitrum mainnet

Test Steps:

  1. Navigate to Perps with a portfolioMargin account - verify hyperLiquidModeFoldsSpot returns true for 'portfolioMargin' mode
  2. Verify availableToTradeBalance is populated with the combined spot+perps balance
  3. Open the withdraw flow - verify the balance shown and max amount use availableToTradeBalance
  4. Verify the Pay-with sheet shows the correct combined balance
  5. Verify the insufficient balance alert uses availableToTradeBalance for comparison
  6. Verify HL_ABSTRACTION_WIRE constants are correctly defined (disabled='i', unifiedAccount='u', portfolioMargin='p')

Expected Outcomes:

  • portfolioMargin mode is treated identically to unifiedAccount for spot folding purposes
  • hyperLiquidModeFoldsSpot returns true for both 'unifiedAccount' and 'portfolioMargin'
  • All balance surfaces show correct combined balance for portfolioMargin users
  • HL_ABSTRACTION_WIRE wire codes match HyperLiquid API expectations

Excluded Features - Feature Flags Disabled (56)

The following features are disabled via feature flags and should NOT be tested:

  • aiSocialLeaderboardEnabled
  • aiSocialWhatsHappeningEnabled
  • bitcoinTestnetsEnabled
  • brazeBannerHome
  • brazeBannerHomeMinVersion
  • brazeSegmentForwarding
  • configRegistryApiEnabled
  • confirmations_pay_hardware
  • coreMCU589AbtestHubPageDiscoveryTabs
  • earnFeatureFlagTemplate
  • earnMusdConversionRewardsUiEnabled
  • earnMusdQuickConvertEnabled
  • earnPooledStakingServiceInterruptionBannerEnabled
  • earnStablecoinLendingServiceInterruptionBannerEnabled
  • explorePageV2Enabled
  • forceRampsStagingEnvironment
  • fullPageAccountList
  • googleLoginIosUnsupportedBlockingEnabled
  • hapticsKillSwitch
  • homeTMCU470AbtestTrendingSections
  • legacyIosGoogleConfigEnabled
  • moneyActivityMockDataEnabled
  • moneyEnableMoneyAccount
  • moneyHomeScreenEnabled
  • moneyShowMoneyAccountAddress
  • pepsSamplePhasedRolloutFlag
  • perpsDefaultPayTokenWhenNoBalanceEnabled
  • perpsMyxProviderEnabled
  • perpsPerpGtmOnboardingModalEnabled
  • perpsPerpTradingServiceInterruptionBannerEnabled
  • platformNewLinkHandlerSystem
  • predictBottomSheet
  • predictClobV2UseLegacyClobHost
  • predictExtendedSportsMarkets
  • predictHotTab
  • predictMarketHighlights
  • predictTabFeaturedCarousel
  • predictUpDown
  • predictWithAnyToken
  • rewardsAnnouncementModalEnabled
  • rewardsBitcoinEnabled
  • rewardsDropsEnabled
  • rewardsEnableMusdDeposit
  • rewardsEnableMusdHolding
  • rewardsMissingEnrolledAccounts
  • rewardsReferralCodeEnabled
  • rewardsReferralEnabled
  • rewardsTronEnabled
  • solanaOnboardingModal
  • solanaTestnetsEnabled
  • tempoConfig
  • tokenDetailsV2ButtonLayout
  • tokenDiscoveryBrowserEnabled
  • tokenListSecurityBadges
  • tronStaking
  • walletHomeOnboardingSteps

Generated by AI Test Plan Analyzer (claude-sonnet-4-6) at 2026-05-05T18:02:08.219Z

AI generated test plan (JSON): Available as artifact test-plan-7.75.1 in the build workflow

@chloeYue
Copy link
Copy Markdown
Contributor Author

chloeYue commented May 6, 2026

policy-bot: approve

<!--
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 -->
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

🔍 Smart E2E Test Selection

⏭️ Smart E2E selection skipped - base branch is not main or a release branch (base: stable)

All E2E tests pre-selected.

View GitHub Actions results

@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​axios@​1.15.29010010096100

View full report

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

E2E Fixture Validation — Schema is up to date
12 value mismatches detected (expected — fixture represents an existing user).
View details

@chloeYue chloeYue requested a review from sleepytanya May 6, 2026 08:48
@chloeYue
Copy link
Copy Markdown
Contributor Author

chloeYue commented May 6, 2026

policy-bot: approve

@chloeYue chloeYue merged commit 37ee996 into stable May 6, 2026
870 of 899 checks passed
@chloeYue chloeYue deleted the release/7.75.1 branch May 6, 2026 18:29
@github-actions github-actions Bot locked and limited conversation to collaborators May 6, 2026
@chloeYue chloeYue restored the release/7.75.1 branch May 6, 2026 18:32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants