0xMiden / 0xMiden/wallet-adapter

MidenFiSignerProvider.connect() opens Chrome Web Store URL when readyState !== Installed, redirects to Play Store on mobile UAs

Aperta Adatta ai principianti
#82 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
TypeScript
Stelle
2
Fork
9
Merge medio
25m
PR unite (30g)
1

Descrizione

**Title**: `MidenFiSignerProvider.connect()` opens Chrome Web Store URL when `readyState !== Installed`, redirects to Play Store on mobile UAs

### Summary

When a consumer's UI calls `connect()` before the adapter has detected `window.midenWallet` / `window.miden` (readyState is `NotDetected` or `Unsupported`), `MidenFiSignerProvider` silently opens `adapter.url` in a new tab as a side effect of the call. `adapter.url` is the Chrome Web Store listing for the MidenFi extension. On mobile Chrome / mobile-UA browsers, Chrome Web Store redirects to the **Google Play Store**, which has nothing to do with the Chrome extension — a confusing UX.

### Repro

1. Consumer's button calls `connect()` immediately on click (e.g. from `useSigner().connect` in `@miden-sdk/react`, or directly from `useMidenFiWallet().connect`).
2. User clicks the button before the adapter's 1-second polling (`scopePollingDetectionStrategy`) has detected the extension — or in an environment where detection is delayed (COOP/COEP-isolated dev servers, slow content-script injection, etc.).
3. `readyState` is still `NotDetected`.
4. Observed on mobile: a Play Store page opens.

Code path: [`packages/core/react/MidenFiSignerProvider.tsx#L391-L404`](https://github.com/0xMiden/wallet-adapter/blob/main/packages/core/react/MidenFiSignerProvider.tsx#L391-L404)

```ts
if (
!(
readyState === WalletReadyState.Installed ||
readyState === WalletReadyState.Loadable
)
) {
setName(null);
if (typeof window !== 'undefined') {
window.open(adapter.url, '_blank'); // ← opens Chrome Web Store
}
throw handleError(new WalletNotReadyError());
}
```

And [`packages/wallets/miden/adapter.ts#L87`](https://github.com/0xMiden/wallet-adapter/blob/main/packages/wallets/miden/adapter.ts#L87):

```ts
url = 'https://chromewebstore.google.com/detail/miden-wallet/ablmompanofnodfdkgchkpmphailefpb';
```

### Why this is a UX problem

1. **Unexpected side effect**: the calling code may not want a new tab opened — e.g. an app that wants to show an in-page "Install MidenFi" card. The call site has no way to suppress the tab open.
2. **Mobile redirect chain**: Chrome Web Store → Play Store is a dead end for users trying to use a Chrome extension. At best it's confusing, at worst it suggests the app is broken.
3. **Race-condition trigger**: even for a user who *has* the extension installed, clicking fast enough (or before the ~1 s polling interval fires the first time) triggers the fallback. Users perceive this as "I installed the wallet and it still sends me to install it again."
4. **Not surfaceable**: the tab-open happens *before* `WalletNotReadyError` is thrown, so even if the app catches the error and shows a custom message, the unwanted tab has already opened.

### Suggested fixes (pick one or combine)

**A. Remove the `window.open` fallback entirely; throw only.**
Let the application decide what to do with `WalletNotReadyError`. Apps that want the store link can render it themselves. This is the cleanest fix and matches how Solana's wallet-adapter stack evolved (they removed automatic redirects for the same reason years ago).

**B. Move the tab-open behind an opt-in prop.**
Add a `redirectToStoreOnNotReady?: boolean` prop on `MidenFiSignerProvider` (default `false`). Preserves the old behavior for anyone relying on it, but makes it explicit.

**C. Detect mobile UAs and suppress the open.**
Simple UA check before `window.open` — if the browser is mobile Chrome / anything that can't actually install the extension, just throw. Less clean than (A) but targets the worst case directly.

### What I ended up doing in my template

Switched from `useSigner()` (which exposes no `readyState`) to `useMidenFiWallet()` and gate the Connect button on `readyState === Installed | Loadable`. While correct, it's worth noting that a consumer using the generic `useSigner()` abstraction (from `@miden-sdk/react`, intended to be wallet-agnostic) has no way to do this gating — they'd have to reach into the MidenFi-specific hook, breaking the abstraction.

### Environment

- `@miden-sdk/miden-wallet-adapter-react@0.14.3` (latest)
- `@miden-sdk/miden-wallet-adapter-base@0.14.3` (latest)
- `@miden-sdk/miden-wallet-adapter-miden@0.14.3`
- Verified on main branch (commit at time of filing); the `window.open` call still present at `packages/core/react/MidenFiSignerProvider.tsx:401`.

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

The issue is in packages/core/react/MidenFiSignerProvider.tsx lines 391-404 and packages/wallets/miden/adapter.ts line 87. Start by reading the connect() method and the readyState logic. Understand the WalletReadyState enum and the detection strategy. The fix involves modifying the conditional to either remove the window.open call or add a prop to control it. Test by simulating the NotDetected state and checking that no unwanted tab opens.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
react, typescript
Ambito
developer-experience, frontend
Tipo di issue
Bug
Difficoltà
2/5
Tempo stimato
1-3 ore
Stato di attività
Tranquilla
Chiarezza
Specificata chiaramente
Idoneità per principianti
65/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.