Skip to content

chore(runway): cherry-pick fix(predict): prevent token selector from using stale approvals from other flows cp-7.73.0#28699

Open
runway-github[bot] wants to merge 1 commit intorelease/7.73.0from
runway-cherry-pick-7.73.0-1775862893
Open

chore(runway): cherry-pick fix(predict): prevent token selector from using stale approvals from other flows cp-7.73.0#28699
runway-github[bot] wants to merge 1 commit intorelease/7.73.0from
runway-cherry-pick-7.73.0-1775862893

Conversation

@runway-github
Copy link
Copy Markdown
Contributor

@runway-github runway-github bot commented Apr 10, 2026

Description

A user reported that the "Pay with" token selector on
PredictBuyWithAnyTokenwasn't allowing to select a different token. A
transaction is needed to that work and the current logic could pick up
pending approvals from unrelated flows (bridge, swap, send, etc.),
allowing them to select tokens from the wrong transaction context.

Root cause: initPayWithAnyToken() calls addTransactionBatch()
directly without first rejecting existing pending approvals — unlike the
standalone predictDeposit flow which goes through
useConfirmNavigation and rejects all unapproved transactions before
creating its own. When stale approvals existed, useApprovalRequest()
returned the first (wrong) approval, and PredictPayWithRow enabled
token selection based on a generic transactionMeta truthiness check.

Fix (defense-in-depth):

  1. usePredictBuyActions — added rejectPendingTransactions() in
    the transitionEnd handler before initPayWithAnyToken(), mirroring
    the cleanup pattern from useConfirmNavigation.
  2. PredictPayWithRow — replaced the generic transactionMeta
    truthiness check with hasTransactionType(transactionMeta, [TransactionType.predictDepositAndOrder]), so the selector only enables
    for the correct transaction type.

This branch also includes prior commits that handle no-quotes blocking
alerts in the buy flow and disable the pay-with selector until
transaction metadata is ready.

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

Feature: Predict buy-with-any-token token selector isolation

  Scenario: token selector stays disabled when a non-predict approval is pending
    Given user has an unconfirmed swap or bridge transaction pending
    And user navigates to a Predict market buy screen

    When the buy screen finishes loading
    Then the "Pay with" row does not show an arrow icon
    And tapping the "Pay with" row does not open the token selection modal

  Scenario: token selector enables after deposit-and-order batch is created
    Given user has no pending transactions
    And user navigates to a Predict market buy screen

    When the buy screen finishes loading and initPayWithAnyToken completes
    Then the "Pay with" row shows the arrow icon
    And tapping the "Pay with" row opens the token selection modal

  Scenario: stale approvals are rejected on buy screen entry
    Given user has an unconfirmed transaction from another flow
    And user navigates to a Predict market buy screen

    When the screen transition completes
    Then the stale unconfirmed transaction is rejected
    And a new deposit-and-order batch is created as the only pending approval

Screenshots/Recordings

Before

N/A

After

N/A

Pre-merge author checklist

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

Medium Risk
Touches transaction/approval handling in the Predict buy flow by
programmatically rejecting unapproved transactions and tightening when
the pay-with selector is enabled; regressions could affect in-flight
approvals or block token selection.

Overview
Prevents the PredictBuyWithAnyToken pay-with token selector from
latching onto stale approvals from other flows.

On screen entry, usePredictBuyActions now rejects all unapproved
transactions before calling initPayWithAnyToken, and
PredictPayWithRow only enables navigation/UI affordances when the
current transactionMeta is a TransactionType.predictDepositAndOrder
(otherwise it disables press, hides the arrow, and removes the muted
background). The buy flow also propagates blocking pay alerts
(insufficient balance / no quotes) via usePredictBuyInfo into
usePredictBuyConditions and usePredictBuyError to disable placing
bets and surface the correct blocking message, with updated tests.

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

[43b030d](https://github.com/MetaMask/metamask-mobile/commit/43b030de60b927736894e6d60001dccdc6933d70)

…using stale approvals from other flows cp-7.73.0 (#28685)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **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?
-->

A user reported that the "Pay with" token selector on
`PredictBuyWithAnyToken`wasn't allowing to select a different token. A
transaction is needed to that work and the current logic could pick up
pending approvals from unrelated flows (bridge, swap, send, etc.),
allowing them to select tokens from the wrong transaction context.

**Root cause:** `initPayWithAnyToken()` calls `addTransactionBatch()`
directly without first rejecting existing pending approvals — unlike the
standalone `predictDeposit` flow which goes through
`useConfirmNavigation` and rejects all unapproved transactions before
creating its own. When stale approvals existed, `useApprovalRequest()`
returned the first (wrong) approval, and `PredictPayWithRow` enabled
token selection based on a generic `transactionMeta` truthiness check.

**Fix (defense-in-depth):**

1. **`usePredictBuyActions`** — added `rejectPendingTransactions()` in
the `transitionEnd` handler before `initPayWithAnyToken()`, mirroring
the cleanup pattern from `useConfirmNavigation`.
2. **`PredictPayWithRow`** — replaced the generic `transactionMeta`
truthiness check with `hasTransactionType(transactionMeta,
[TransactionType.predictDepositAndOrder])`, so the selector only enables
for the correct transaction type.

This branch also includes prior commits that handle no-quotes blocking
alerts in the buy flow and disable the pay-with selector until
transaction metadata is ready.

## **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: Predict buy-with-any-token token selector isolation

  Scenario: token selector stays disabled when a non-predict approval is pending
    Given user has an unconfirmed swap or bridge transaction pending
    And user navigates to a Predict market buy screen

    When the buy screen finishes loading
    Then the "Pay with" row does not show an arrow icon
    And tapping the "Pay with" row does not open the token selection modal

  Scenario: token selector enables after deposit-and-order batch is created
    Given user has no pending transactions
    And user navigates to a Predict market buy screen

    When the buy screen finishes loading and initPayWithAnyToken completes
    Then the "Pay with" row shows the arrow icon
    And tapping the "Pay with" row opens the token selection modal

  Scenario: stale approvals are rejected on buy screen entry
    Given user has an unconfirmed transaction from another flow
    And user navigates to a Predict market buy screen

    When the screen transition completes
    Then the stale unconfirmed transaction is rejected
    And a new deposit-and-order batch is created as the only pending approval
```

## **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**

- [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.

<!-- Generated with the help of the pr-description AI skill -->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches transaction/approval handling in the Predict buy flow by
programmatically rejecting unapproved transactions and tightening when
the pay-with selector is enabled; regressions could affect in-flight
approvals or block token selection.
> 
> **Overview**
> Prevents the `PredictBuyWithAnyToken` pay-with token selector from
latching onto stale approvals from other flows.
> 
> On screen entry, `usePredictBuyActions` now rejects all `unapproved`
transactions before calling `initPayWithAnyToken`, and
`PredictPayWithRow` only enables navigation/UI affordances when the
current `transactionMeta` is a `TransactionType.predictDepositAndOrder`
(otherwise it disables press, hides the arrow, and removes the muted
background). The buy flow also propagates *blocking* pay alerts
(insufficient balance / no quotes) via `usePredictBuyInfo` into
`usePredictBuyConditions` and `usePredictBuyError` to disable placing
bets and surface the correct blocking message, with updated tests.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
69b5397. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@runway-github runway-github bot requested a review from a team as a code owner April 10, 2026 23:15
@github-actions
Copy link
Copy Markdown
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.

@metamaskbot metamaskbot added the team-bots Bot team (for MetaMask Bot, Runway Bot, etc.) label Apr 10, 2026
@github-actions github-actions bot added size-M risk-medium Moderate testing recommended · Possible bug introduction risk labels Apr 10, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePredictions, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 90%
click to see 🤖 AI reasoning details

E2E Test Selection:
All 11 changed files are within the Predict (Polymarket) feature area, specifically the PredictBuyWithAnyToken flow. Key changes include:

  1. usePredictBuyInfo.ts: Now aggregates both useInsufficientPayTokenBalanceAlert and new useNoPayTokenQuotesAlert into a unified blocking alerts system, exposing hasBlockingPayAlerts and blockingPayAlertMessage.

  2. usePredictBuyActions.ts: Added rejectPendingTransactions() that clears unapproved transactions when entering the Pay With Any Token screen - this is a behavioral change that interacts with TransactionController and ApprovalController.

  3. usePredictBuyConditions.ts: Refactored to use generic hasBlockingPayAlerts flag; simplified isPayFeesLoading logic (removed dependency on quotes length).

  4. usePredictBuyError.ts: Accepts blockingPayAlertMessage prop instead of calling the alert hook directly.

  5. PredictPayWithRow.tsx: Fixed canEdit to also require isPredictDepositAndOrder transaction type - prevents editing in non-deposit-and-order flows.

Tag selection rationale:

  • SmokePredictions: Primary tag - changes directly affect the prediction market buying flow (opening positions uses PredictBuyWithAnyToken)
  • SmokeWalletPlatform: Required by SmokePredictions description - Predictions is a section inside the Trending tab
  • SmokeConfirmations: Required by SmokePredictions description - opening/closing positions are on-chain transactions; also relevant because rejectPendingTransactions() interacts with ApprovalController/TransactionController

No other feature areas are impacted - changes are fully contained within the Predict UI components and their hooks.

Performance Test Selection:
No performance-sensitive code paths are changed. The modifications are functional logic changes (alert aggregation, transaction cleanup, edit permission logic) within the Predict feature. No list rendering, heavy data loading, or UI rendering performance impacts are introduced.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk-medium Moderate testing recommended · Possible bug introduction risk size-M team-bots Bot team (for MetaMask Bot, Runway Bot, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants