fix: batch sell tx bridge status bump (#31098)#31488
Conversation
<!-- 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** Fixes Batch Sell (and other gasless EIP-7702) transaction submission when Smart Transactions (STX) and send bundle are both enabled. **Problem:** Quotes with `gasIncluded7702: true` must be published via the EIP-7702 delegation relay (`Delegation7702PublishHook`). When STX and send bundle were enabled, `publishHook` skipped the 7702 path and submitted via STX instead, causing transaction failures. **Changes:** 1. **`@metamask/bridge-status-controller` `^72.0.0` → `^72.0.2`** — picks up the controller fix for the batch-sell submission edge case when `gasIncluded7702=true` and STX is enabled (see package changelog for parameter changes). 2. **`TransactionController` `publishHook`** — when `transactionMeta.isGasFeeIncluded` is true (set by bridge-status-controller for gasless-7702 quotes), attempt `Delegation7702PublishHook` before STX even if STX and send bundle are supported. Aligns with extension client behavior (`isSwapGasIncluded7702`). **Motivation:** The quote/backend contract requires 7702 processing; routing through STX was incorrect for this case. ## **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 Batch Sell transactions failing to submit when gas-included EIP-7702 quotes were used with Smart Transactions enabled ## **Related issues** Refs: MetaMask/core#8979 ## **Manual testing steps** ```gherkin Feature: Batch Sell gas-included 7702 submission with Smart Transactions Scenario: Batch Sell submits successfully when gas is included via 7702 and STX is enabled Given I have an EVM account that supports EIP-7702 And Smart Transactions are enabled on a chain that supports send bundle And Batch Sell is available with multiple eligible source tokens And quotes return with gas included via 7702 (network fee shown as included / gasIncluded7702) When I complete Batch Sell review and submit Sell All Then transactions submit without failure And I am not blocked by incorrect STX-only submission for gasless-7702 quotes Scenario: Normal STX gas-included swap still uses Smart Transactions when isGasFeeIncluded is not set Given Smart Transactions and send bundle are enabled And I initiate a swap with STX gas-included (not gasIncluded7702 / no isGasFeeIncluded on tx meta) When I confirm and submit the transaction Then submission still goes through the Smart Transactions path as before ``` **Commands run locally:** ```bash yarn jest app/core/Engine/controllers/transaction-controller/transaction-controller-init.test.ts -t "7702 delegation hook" ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> N/A ### **After** <!-- [screenshots/recordings] --> 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes transaction submission routing for a specific meta flag; wrong routing could affect Batch Sell and gasless-7702 swaps, but scope is narrow and covered by a new unit test. > > **Overview** > Fixes **Batch Sell** and other **gas-included EIP-7702** flows failing when **Smart Transactions (STX)** and **send bundle** are both on. > > **`publishHook`** now treats `transactionMeta.isGasFeeIncluded` (gasless-7702 quotes from bridge status) like extension’s `isSwapGasIncluded7702`: it tries **`Delegation7702PublishHook`** before STX even when STX and bundle would otherwise win. A unit test asserts the 7702 hook runs and STX is skipped when `isGasFeeIncluded` is true. > > **`@metamask/bridge-status-controller`** is bumped **^72.0.0 → ^72.0.2** so tx meta and submission align with the gas-included-7702 contract; `yarn.lock` reflects related transitive package updates. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7a0a735. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
|
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. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
cf477f9 to
84bc91f
Compare
<!-- 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. --> <!-- mms-check directive vocabulary — read by .github/scripts/shared/pr-template-checks.ts at module load to build the validation plan. Directives are invisible in rendered markdown and must NOT be removed or edited without updating the validator registry. type=text Section must contain non-placeholder prose. type=changelog Section must have a valid CHANGELOG entry: line. type=issue-link Section must have a Fixes:/Closes:/Refs: line with a value. type=manual-testing Section must have real testing steps or an explicit N/A. type=screenshot Section must have evidence (image/URL) or an explicit N/A. type=checklist Section must have all checkboxes consciously checked. required=true|false Whether a missing/invalid section blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> ### `gasless-swap.spec.ts` - Fixed and re-enabled skipped E2E swap test. - Added mocks to match the actual Sentinel API URLs used by the app, and added relay endpoint mocks for the EIP-7702 gasless swap flow, which uses a different transaction submission path than the standard Smart Transactions flow. ### `bridge-action-smoke.spec.ts` - Moved `dismissKeypad()` to **after** the network fee label assertion (instead of before) - The fee label needs time to appear (60s timeout) while the quote is fetched; dismissing the keypad first could interfere with quote loading or obscure the assertion - Waiting for the fee label first, then dismissing the keypad, matches the correct user flow ### `TestSnaps.ts` - Removed `checkStability: true` from date-time picker, date picker, and time picker OK button taps - On iOS, calendar/time picker animations prevent Detox’s stability check from passing, causing the interactive UI snap test to time out - The OK button is stationary; the calendar view above it is what animates ### `onramp-unified-buy.spec.ts` - Fixed a flaky test caused by a race with remote feature flag loading: 1. Seeded V1/V2 flags into `RemoteFeatureFlagController` initial state via `.withRampsUnifiedBuyRemoteFlagsSeededForE2E()`, so flags are available on first render without waiting for the mock server 2. Switched mock server flags from `remoteFeatureFlagRampsUnifiedEnabled` (`minimumVersion: '7.63.0'`) to `remoteFeatureFlagRampsUnifiedMatrixForE2E(true, true)` (`'0.0.0'`), keeping consistency with seeded state if the controller refreshes mid-test ## `stake-action-smoke.spec.ts` - Increased the Earn button visibility timeout from **45s → 60s** - The Earn button depends on balance loading from fixture state, which can take longer on Android / slower CI machines ## **Changelog** <!-- mms-check: type=changelog required=true --> <!-- 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** <!-- mms-check: type=issue-link required=true --> Fixes: test falkiness on stake and bridge tests ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> N/A ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** https://github.com/user-attachments/assets/6d8b3707-917d-46a6-969d-943172f032f2 ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> <!-- 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** > Changes are limited to E2E tests and mock helpers; production wallet code is untouched. > > **Overview** > Stabilizes smoke E2E by tightening waits, mocks, and test ordering—**no production app behavior changes**. > > **Swap / STX mocks:** Sentinel URL matchers now accept versioned `*.api.cx.metamask.io` paths (not only `transaction.api…`). New mocks cover the **EIP-7702 gasless relay** path (`eth_sendRelayTransaction` + relay polling), with a dummy Anvil tx so receipts resolve. **Gasless swap** specs are **re-enabled** (removed `it.skip`). > > **Bridge smoke:** `dismissKeypad()` runs **after** waiting for the network fee label (60s), so quote loading isn’t disrupted. > > **Onramp unified buy:** Fixtures seed unified-buy remote flags via `.withRampsUnifiedBuyRemoteFlagsSeededForE2E()` and mocks use `remoteFeatureFlagRampsUnifiedMatrixForE2E` to avoid flag-load races. > > **Detox / timing:** `waitForAppReady` default **60s**; stake Earn button wait **60s**; TestSnaps picker OK taps drop `checkStability` on iOS where calendar animation blocks stability checks. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 297372c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - PR targets a release or stable branch (release/* or stable) All E2E tests pre-selected. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 6309f03. Configure here.
| }, | ||
| ], | ||
| }, | ||
| })); |
There was a problem hiding this comment.
Relay mock success without hash
Medium Severity
The 7702 relay GET mock always returns VALIDATED, even when the Anvil impersonation/send step failed and relayTxHash was never set. The publish hook then treats relay as successful with a missing transactionHash, so EIP-7702 gasless E2E can fail or flake instead of surfacing the mock setup error.
Reviewed by Cursor Bugbot for commit 6309f03. Configure here.


Description
Fixes Batch Sell (and other gasless EIP-7702) transaction submission when Smart Transactions (STX) and send bundle are both enabled.
Problem: Quotes with
gasIncluded7702: truemust be published via the EIP-7702 delegation relay (Delegation7702PublishHook). When STX and send bundle were enabled,publishHookskipped the 7702 path and submitted via STX instead, causing transaction failures.Changes:
@metamask/bridge-status-controller^72.0.0→^72.0.2— picks up the controller fix for the batch-sell submission edge case whengasIncluded7702=trueand STX is enabled (see package changelog for parameter changes).TransactionControllerpublishHook— whentransactionMeta.isGasFeeIncludedis true (set by bridge-status-controller for gasless-7702 quotes), attemptDelegation7702PublishHookbefore STX even if STX and send bundle are supported. Aligns with extension client behavior (isSwapGasIncluded7702).Motivation: The quote/backend contract requires 7702 processing; routing through STX was incorrect for this case.
Changelog
CHANGELOG entry: Fixed Batch Sell transactions failing to submit when gas-included EIP-7702 quotes were used with Smart Transactions enabled
Related issues
Refs: #31484
Manual testing steps
Commands run locally:
yarn jest app/core/Engine/controllers/transaction-controller/transaction-controller-init.test.ts -t "7702 delegation hook"Screenshots/Recordings
Before
N/A
After
N/A
Pre-merge author checklist
Performance checks (if applicable)
trace()for usage andaddTokenfor an exampleFor performance guidelines and tooling, see the Performance Guide.
Pre-merge reviewer checklist
Note
Medium Risk
Changes which publish path runs for gas-included transactions when STX is enabled—a core submission decision—but scope is gated on
isGasFeeIncludedwith new unit and E2E coverage.Overview
Fixes Batch Sell and other gas-included EIP-7702 flows that were incorrectly published through Smart Transactions when STX and send bundle were enabled.
Transaction publish routing now treats
transactionMeta.isGasFeeIncludedas gas-included 7702 (isSwapGasIncluded7702) and runsDelegation7702PublishHook(Sentinel relay) before STX, even when STX + send bundle would otherwise win. A unit test asserts STX is not called when that flag is set.@metamask/bridge-status-controlleris bumped to^72.0.2so tx meta gets the right gas-included-7702 signaling (with related lockfile/controller dependency updates).E2E/support: STX HTTP mocks accept versioned
*.api.cx.metamask.iopaths; 7702 relay submit/poll mocks were added (Anvil-backed receipt). Gasless swap smoke tests are re-enabled; ramps unified-buy fixtures/flags, longer app-ready/stake timeouts, bridge quote keypad timing, and minor TestSnaps tap stability tweaks.Reviewed by Cursor Bugbot for commit 6309f03. Bugbot is set up for automated code reviews on this repo. Configure here.