Skip to content

fix: prevent WalletConnect session proposal race conditions (WAPI-1070)#26121

Open
chakra-guy wants to merge 1 commit intoad/in-app-qr-code-universal-link-ios-bugfrom
fix/wapi-1070-on-qr-fix
Open

fix: prevent WalletConnect session proposal race conditions (WAPI-1070)#26121
chakra-guy wants to merge 1 commit intoad/in-app-qr-code-universal-link-ios-bugfrom
fix/wapi-1070-on-qr-fix

Conversation

@chakra-guy
Copy link
Contributor

@chakra-guy chakra-guy commented Feb 16, 2026

Description

Fixes a set of race conditions in the WalletConnect v2 connection flow that caused a "stuck" or looping connection tray when scanning QR codes. The root cause was multiple layers of concurrent/duplicate processing:

  1. Duplicate OS deeplink delivery:
    The OS can deliver the same deeplink 3-5 times via Linking + Branch. Each delivery called pair() and pushed a loading modal, stacking duplicate modals on screen.
  2. Duplicate relay events:
    The WalletConnect relay can fire the same session_proposal event multiple times when duplicate pair() calls were made, causing duplicate AccountConnect screens.
  3. Concurrent proposal handling:
    Rapid QR scans caused overlapping proposals to fight over shared state (wc2Metadata, navigation, approval queue).
  4. Navigation re-trigger loop:
    Changes to the pendingApprovals Redux state re-triggered PermissionApproval's useEffect, causing repeated navigation to AccountConnect for the same approval.

Each issue is fixed at the layer where it occurs:

Layer Guard Purpose
connect() seenTopics + 5 s TTL Blocks duplicate OS deeplink deliveries; TTL allows manual retries
onSessionProposal() proposalLock Serializes concurrent proposals
_handleSessionProposal() handledProposalIds Blocks duplicate relay events
PermissionApproval lastNavigatedApprovalIdRef Prevents re-navigation for the same approval ID

Additionally fixes the SDKLoading Lottie animation not being visible.

Compatibility with #24040: The PermissionApproval change keeps pendingApprovals in the useEffect deps (so the effect still re-runs when the queue changes, preventing stuck approvals). The added ref guard only skips navigation for the same approval ID; new approvals with a different ID navigate normally.

Changelog

CHANGELOG entry: Fixed WalletConnect connection tray getting stuck or looping when scanning QR codes, and fixed the loading animation not displaying during connection.

Related issues

Fixes: WAPI-1070

Manual testing steps

Feature: WalletConnect QR code connection

  Scenario: In-app QR scanner connection
    Given the user opens a dApp that supports WalletConnect (e.g. Coinbase Commerce)
    When the user scans the WC QR code using the in-app scanner
    Then a loading animation should briefly appear
    And the AccountConnect approval screen should appear once
    And tapping Connect should complete the connection

  Scenario: Camera app deeplink connection
    Given the user opens a dApp that supports WalletConnect
    When the user scans the WC QR code using the device camera app
    Then the loading modal should appear only once (not duplicated)
    And the AccountConnect screen should appear once
    And tapping Connect should complete the connection

  Scenario: Rapid repeated scans
    Given the user has completed one connection via QR scan
    When the user immediately scans another WC QR code
    Then each scan should produce exactly one connection flow
    And no flows should get stuck or loop

  Scenario: Retry after failed relay delivery
    Given the user scans a QR code but the WC relay fails to send a session_proposal
    When the user waits ~5 seconds and scans the same QR code again
    Then a new connection attempt should proceed normally

Screenshots/Recordings

Screen.Recording.2026-02-16.at.14.16.502.mov

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs and MetaMask Mobile Coding Standards.
  • 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 format if applicable
  • I've applied the right labels on the PR

Note

Medium Risk
Touches WalletConnect connection/proposal handling and approval navigation, where subtle timing/dedup logic could cause missed or delayed connection prompts. Changes are scoped with guards/timeouts and include a targeted test update.

Overview
Fixes WalletConnect v2 QR/deeplink connection loops by deduplicating and serializing key parts of the flow: WC2Manager.connect() ignores duplicate pairing topics for a short TTL, onSessionProposal() now runs behind a serialized lock with a safety timeout, and _handleSessionProposal() ignores duplicate proposal IDs and clears stale wc2Metadata on rejection.

Prevents PermissionApproval from re-navigating to AccountConnect when pendingApprovals changes but the current approval ID is unchanged (covered by an updated test), and fixes the SDK loading tray animation sizing by adding an explicit aspectRatio based on the Lottie asset’s intrinsic dimensions. Minor logging cleanup in legacy deeplink handlers.

Written by Cursor Bugbot for commit e71ce4b. This will update automatically on new commits. Configure here.

@github-actions
Copy link
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 team-wallet-integrations Wallet Integrations team INVALID-PR-TEMPLATE PR's body doesn't match template labels Feb 16, 2026
@github-actions
Copy link
Contributor

🔍 Smart E2E Test Selection

⏭️ Smart E2E selection skipped - base branch is not main (base: ad/in-app-qr-code-universal-link-ios-bug)

All E2E tests pre-selected.

View GitHub Actions results

@chakra-guy chakra-guy marked this pull request as ready for review February 16, 2026 13:21
@chakra-guy chakra-guy requested review from a team as code owners February 16, 2026 13:21
Copy link

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

@sonarqubecloud
Copy link

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

Labels

INVALID-PR-TEMPLATE PR's body doesn't match template size-S team-wallet-integrations Wallet Integrations team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants