release: 8.4.3 (OTA) - #34520
Draft
metamask-ci[bot] wants to merge 9 commits into
Draft
Conversation
…oller cp-8.5.0 (#33822) ## **Description** Perps orders funded with a custom pay token fail at publish with `MetaMask Pay: Cannot submit without quote`. The publish guard is not the cause; it is the last thing to notice a problem that starts on the order screen. The order amount reaches `TransactionPayController` through a chain of effects: `depositAmount` sets the pending amount, then `amountHuman` triggers `updateTokenAmount`. Until that lands, the required token still has `amountRaw: "0"`. A zero required amount produces no source amounts, so no quote is ever requested. Nothing gates the Place Order button in that window. `shouldBlockBecauseOfFeesLoading` only reads `isPayTotalsLoading`, which is false because the fetch has not started, and the no-quotes alert cannot fire because it needs a non-empty `sourceAmounts`. Tapping there sends an unfunded deposit to publish, which correctly rejects it. Logs from a local build show the window lasting about three seconds after the payment token changes, with loading false, no quotes, and the required amount still zero. The app even emits `Perp Trade Quote Received` with `status: success` and `0ms` latency during it. This change treats a stale pay amount as "not ready", so the CTA stays disabled until the controller has the real amount. Predict already solved the same problem with its `isPaySystemSettling` machine in `usePredictBuyConditions`; Perps never had an equivalent. Porting that machine over is the fuller fix and is worth a follow-up, but this keeps the hotfix small and cannot leave the button stuck, because the amount always arrives. The publish guard is left exactly as it is. It is the correct backstop, and loosening it would only turn a visible error back into a silent unfunded deposit. ## **Changelog** CHANGELOG entry: Fixed a bug that stopped some Perps orders from being placed when paying with another token ## **Related issues** Fixes: CONF-1731 ## **Manual testing steps** ~~~gherkin Feature: Perps order paying with another token Scenario: user taps Place Order before the pay amount is ready Given the user opens a Perps market and chooses Long And the user changes "Pay with" to a token that is not Arbitrum USDC When the user taps Place Order as soon as the button looks tappable Then the button stays disabled until the fees have settled And no "Cannot submit without quote" error is raised Scenario: user places the order after the fees settle Given the user selected a custom pay token And the fees and quote have finished loading When the user taps Place Order Then the deposit and order are submitted as before Scenario: user pays from the existing Perps balance Given the Perps balance is selected as the payment method When the user taps Place Order Then the order is placed directly with no deposit transaction ~~~ ## **Screenshots/Recordings** N/A — no visual change. The only difference is that an existing button stays disabled for a few seconds longer while the pay amount propagates. ### **Before** Tapping Place Order in the window right after changing the pay token fails with a "Deposit failed" toast. Reproduced on `main` with debug logging, which captured the full chain: the pay state with `amountRaw: "0"` and no executable quote, the publish-guard throw `MetaMask Pay: Cannot submit without quote`, and the failed transaction with no hash. The same user-facing toast also reproduces on 8.2.0 from a real device, before that publish guard existed, so the ungated CTA window predates 8.3.0; the guard only made the failure visible. ### **After** The button remains disabled through that window and the order submits normally once the quote is ready. Verified on this branch with the same logging: the window still appears, with loading false, no quotes and a zero amount for about three seconds, but no tap reaches publish, no guard error is raised, and no toast is shown. ## **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** > Touches Perps order submission gating and MetaMask Pay readiness for custom tokens; logic is narrow but user-facing on a money path. > > **Overview** > Fixes a race where **Place Order** could stay enabled right after switching to a custom pay token, because quote loading was still false while `TransactionPayController` still had `amountRaw: "0"` and never requested a quote—leading to **Cannot submit without quote** on publish. > > `PerpsOrderView` now reads **`useTransactionPayRequiredTokens`** and treats a stale pay amount (`amountRaw === '0'` for tokens that are not `skipIfBalance`) as **not ready**, alongside existing pay-quote loading. That **`isPayStateNotReady`** flag feeds **`shouldBlockBecauseOfFeesLoading`** and fee-loading UI for custom-token flows only; paying from the Perps balance is unchanged. > > Tests mock required tokens and assert the button stays disabled with a zero amount, enables once a real amount arrives, ignores zero amounts when balance covers the token, and does not block Perps-balance orders. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1e58769. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…33962) - fix: route WalletConnect relay through built-in WebSocket (#33871) ## **Description** **What:** Routes `relay.walletconnect.org` / `relay.walletconnect.com` through React Native's built-in WebSocket instead of the Nitro adapter (hostname match, both prod and dev installs). Every other endpoint keeps the Nitro transport, so the performance work from #32472 is untouched. **Why:** #32472 (shipped in 8.3.0) replaced `global.WebSocket` with `react-native-nitro-websockets`. Its Android native layer (`WebSocketConnection.cpp` `connect()`) sends `Sec-WebSocket-Protocol: nitro-ws` (libwebsockets transmits `lws_client_connect_info.protocol` as that request header) and an `Origin` header set to the server's own host on every connection whose caller requested no subprotocol — which is exactly what WalletConnect's transport does (`new WebSocket(url, [], undefined)`). The WalletConnect relay rejects that handshake, the relay socket never opens, `pairing.pair()` never settles, and every WalletConnect connection on Android 8.3.0 hangs on the "Connecting to MetaMask…" sheet. Lenient endpoints (e.g. HyperLiquid feeds) ignore the extra headers, which is why all other websocket features work and this slipped through. [Slack thread where the issue is first surfaced](https://consensys.slack.com/archives/C08U6DYNJ1G/p1785165035226969) Android-only because the package's iOS implementation (`NWWebSocketConnection.mm`, NSURLSession) only sets `Sec-WebSocket-Protocol` when protocols are actually requested and sets no Origin. Root-cause proof (A/B test on emulator): with only the relay host routed through the built-in WebSocket and everything else on Nitro, the relay connects immediately and the session proposal → approval → `wc_sessionSettle` flow completes end-to-end (verified from the dapp side via CDP). A follow-up to fix the Android native layer itself (bind the lws callback via `local_protocol_name`, leave `protocol` null when no subprotocol is requested, drop the fabricated `Origin`) is tracked in WAPI-1574; once that lands this bypass can be removed. ## **Changelog** CHANGELOG entry: Fixed WalletConnect connections hanging forever on Android. ## **Related issues** Fixes: [WAPI-1574](https://consensyssoftware.atlassian.net/browse/WAPI-1574) Refs: #32472 ## **Manual testing steps** Feature: WalletConnect pairing on Android Scenario: user connects a dapp via WalletConnect Given MetaMask Android (8.3.0 or main) with an unlocked wallet When user taps WalletConnect → MetaMask on https://metamask.github.io/test-dapp/ (or Hyperliquid) and approves the permissions sheet Then the loading sheet resolves, the session settles, and the dapp shows the connected account Scenario: other websocket consumers stay on Nitro Given the fix applied When user opens Perps and Predictions (Polymarket) Then prices and positions still update live over the Nitro WebSocket transport ## **Screenshots/Recordings** ### **Before** WalletConnect relay socket fails on every attempt; `pairing.pair()` never settles; "Connecting to MetaMask…" sheet hangs indefinitely. ### **After** Relay connects immediately; session proposal → approval → settle completes; dapp receives `wc_sessionSettle` within a second of approval. ## **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. ## **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. [WAPI-1574]: https://consensyssoftware.atlassian.net/browse/WAPI-1574?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches global `WebSocket` routing used by WalletConnect and all `wss` traffic; behavior is well-tested but any hostname-routing bug could affect connectivity or regress Nitro performance paths. > > **Overview** > Fixes Android WalletConnect hangs by **not** sending `relay.walletconnect.org` / `relay.walletconnect.com` through the Nitro WebSocket adapter, which adds handshake headers the relay rejects. > > **Production** no longer replaces `global.WebSocket` with Nitro only. It installs a **routing constructor** that keeps Nitro for compatible `wss` URLs and delegates WalletConnect relay URLs (and non-string URLs like `URL` objects) to React Native’s built-in `WebSocket`. **Dev** keeps `ws://` on the built-in socket and `wss://` on Nitro, but applies the same relay bypass for `wss` relay hosts. > > Hostname matching is done with a lightweight `getWsHostname` parser (ports, userinfo, query-string false positives). Re-install is **idempotent** via a symbol so Fast Refresh/tests don’t nest wrappers. Missing built-in `WebSocket` still falls back to bare Nitro but now **logs a warning** that relay routing is lost. > > Tests cover relay routing in dev and prod, other hosts staying on Nitro, WalletConnect’s `(url, [], undefined)` shape, and the no-built-in warning. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4558569. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [80fcbb9](80fcbb9) [WAPI-1574]: https://consensyssoftware.atlassian.net/browse/WAPI-1574?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ Co-authored-by: Alex Donesky <adonesky@gmail.com>
Runway bumped your version to 8.4.1 Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com>
…33979) - feat(perps): block place order until the pay amount reaches the controller cp-8.5.0 (#33822) ## **Description** Perps orders funded with a custom pay token fail at publish with `MetaMask Pay: Cannot submit without quote`. The publish guard is not the cause; it is the last thing to notice a problem that starts on the order screen. The order amount reaches `TransactionPayController` through a chain of effects: `depositAmount` sets the pending amount, then `amountHuman` triggers `updateTokenAmount`. Until that lands, the required token still has `amountRaw: "0"`. A zero required amount produces no source amounts, so no quote is ever requested. Nothing gates the Place Order button in that window. `shouldBlockBecauseOfFeesLoading` only reads `isPayTotalsLoading`, which is false because the fetch has not started, and the no-quotes alert cannot fire because it needs a non-empty `sourceAmounts`. Tapping there sends an unfunded deposit to publish, which correctly rejects it. Logs from a local build show the window lasting about three seconds after the payment token changes, with loading false, no quotes, and the required amount still zero. The app even emits `Perp Trade Quote Received` with `status: success` and `0ms` latency during it. This change treats a stale pay amount as "not ready", so the CTA stays disabled until the controller has the real amount. Predict already solved the same problem with its `isPaySystemSettling` machine in `usePredictBuyConditions`; Perps never had an equivalent. Porting that machine over is the fuller fix and is worth a follow-up, but this keeps the hotfix small and cannot leave the button stuck, because the amount always arrives. The publish guard is left exactly as it is. It is the correct backstop, and loosening it would only turn a visible error back into a silent unfunded deposit. ## **Changelog** CHANGELOG entry: Fixed a bug that stopped some Perps orders from being placed when paying with another token ## **Related issues** Fixes: CONF-1731 ## **Manual testing steps** ~~~gherkin Feature: Perps order paying with another token Scenario: user taps Place Order before the pay amount is ready Given the user opens a Perps market and chooses Long And the user changes "Pay with" to a token that is not Arbitrum USDC When the user taps Place Order as soon as the button looks tappable Then the button stays disabled until the fees have settled And no "Cannot submit without quote" error is raised Scenario: user places the order after the fees settle Given the user selected a custom pay token And the fees and quote have finished loading When the user taps Place Order Then the deposit and order are submitted as before Scenario: user pays from the existing Perps balance Given the Perps balance is selected as the payment method When the user taps Place Order Then the order is placed directly with no deposit transaction ~~~ ## **Screenshots/Recordings** N/A — no visual change. The only difference is that an existing button stays disabled for a few seconds longer while the pay amount propagates. ### **Before** Tapping Place Order in the window right after changing the pay token fails with a "Deposit failed" toast. Reproduced on `main` with debug logging, which captured the full chain: the pay state with `amountRaw: "0"` and no executable quote, the publish-guard throw `MetaMask Pay: Cannot submit without quote`, and the failed transaction with no hash. The same user-facing toast also reproduces on 8.2.0 from a real device, before that publish guard existed, so the ungated CTA window predates 8.3.0; the guard only made the failure visible. ### **After** The button remains disabled through that window and the order submits normally once the quote is ready. Verified on this branch with the same logging: the window still appears, with loading false, no quotes and a zero amount for about three seconds, but no tap reaches publish, no guard error is raised, and no toast is shown. ## **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** > Touches Perps order submission gating and MetaMask Pay readiness for custom tokens; logic is narrow but user-facing on a money path. > > **Overview** > Fixes a race where **Place Order** could stay enabled right after switching to a custom pay token, because quote loading was still false while `TransactionPayController` still had `amountRaw: "0"` and never requested a quote—leading to **Cannot submit without quote** on publish. > > `PerpsOrderView` now reads **`useTransactionPayRequiredTokens`** and treats a stale pay amount (`amountRaw === '0'` for tokens that are not `skipIfBalance`) as **not ready**, alongside existing pay-quote loading. That **`isPayStateNotReady`** flag feeds **`shouldBlockBecauseOfFeesLoading`** and fee-loading UI for custom-token flows only; paying from the Perps balance is unchanged. > > Tests mock required tokens and assert the button stays disabled with a zero amount, enables once a real amount arrives, ignores zero amounts when balance covers the token, and does not block Perps-balance orders. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1e58769. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [e817797](e817797)
The zip artifact path used by the EAS/OTA pipelines strips Unix executable bits, so consumers rely on restore-node-modules-permissions to put them back. Its globs required an exact "bin" path segment, which never matched the platform-suffixed directories hermes-compiler uses (linux64-bin, osx-bin, win64-bin). Metro spawns that binary directly during bundling, so OTA pushes failed with EACCES once React Native 0.83.6 moved hermesc out of the react-native package, where it had lived under sdks/ and was covered incidentally. Also covers *.sh scripts, which are spawned directly by Xcode build phases and packager helpers and carry the same exposure on this path. Co-authored-by: Cursor <cursoragent@cursor.com>
…s (8.4.1) (#34005) ## **Description** Backport of #34004 to unblock the `8.4.1` OTA release. **This backport is required separately** because CI composite actions resolve from the checked-out branch, not from `main`. `Runway OTA RC` is dispatched against `release/8.4.1-ota`, so it uses that branch's copy of `.github/actions/restore-node-modules-permissions` — meaning the `main` fix alone does not affect this release. Failing run: https://github.com/MetaMask/metamask-mobile/actions/runs/30454324689/job/90593099632 ``` Error: spawn .../node_modules/hermes-compiler/hermesc/linux64-bin/hermesc EACCES ``` Both `Push EAS Update (iOS)` and `Push EAS Update (Android)` fail at Metro bundling because `hermesc` lost its executable bit in the zip artifact round-trip and the permission-restore globs required an exact `bin` path segment, never matching `hermes-compiler`'s `linux64-bin` / `osx-bin` / `win64-bin` layout. Full root-cause analysis, blast-radius review, and testing notes are in #34004. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: OTA push for 8.4.1 Scenario: Runway OTA RC after backport Given this PR is merged into release/8.4.1-ota When Runway OTA RC is re-run for 8.4.1 Then Push EAS Update (iOS) and (Android) bundle without EACCES ``` After merge, re-run **Runway OTA RC** for `8.4.1`. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Note for other release branches** `release/8.4.0` and `release/8.5.0` carry the same combination (RN `0.83.6` plus the un-patched action) and will hit this on their next OTA push, so they likely want the same backport. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] 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. Made with [Cursor](https://cursor.com)
Contributor
|
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. |
Contributor
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - PR targets a release or stable branch (release/* or stable) All E2E tests pre-selected. |
tommasini
approved these changes
Aug 8, 2026
|
tommasini
temporarily deployed
to
build-production
August 8, 2026 09:33 — with
GitHub Actions
Inactive
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.



OTA hotfix: branch
release/8.4.3-ota.OTA_VERSIONinapp/constants/ota.tsisv8.4.3.8.4.3/v8.4.3; the-otasuffix is branch-only.