Skip to content

Provider.create() crashes calling window.dispatchEvent — announceProvider guard misses window.dispatchEvent/addEventListener check #730

Description

@christopherwxyz

Describe the bug

Provider.create()'s EIP-6963 wallet-announcement code guards on window, CustomEvent, and crypto.randomUUID being defined before calling mipd's announceProvider, but doesn't check for window.dispatchEvent/window.addEventListener themselves:

https://github.com/tempoxyz/accounts/blob/main/src/core/Provider.ts#L1821-L1841

if (
  typeof window !== 'undefined' &&
  typeof CustomEvent !== 'undefined' &&
  typeof crypto.randomUUID === 'function'
) {
  const rdns = adapter.rdns ?? `com.${(adapter.name ?? 'Injected Wallet').toLowerCase().replace(/\s+/g, '')}`
  if (!announced.has(rdns)) {
    announced.add(rdns)
    announceProvider({
      info: { icon: adapter.icon ?? defaultIcon, name: adapter.name ?? 'Injected Wallet', rdns, uuid: crypto.randomUUID() },
      provider,
    } as never)
  }
}

mipd's announceProvider unconditionally calls window.dispatchEvent(...) and window.addEventListener(...):

https://github.com/wevm/mipd/blob/main/src/utils.ts

In environments that provide a partial window-like global (e.g. React Native, where some setups alias global.window = global and polyfill CustomEvent/crypto.randomUUID for other unrelated reasons, but have no DOM event dispatching), all three guard conditions pass, announceProvider gets called, and window.dispatchEvent throws:

TypeError: undefined is not a function

This crashes Provider.create() entirely — not just the EIP-6963 announcement — since the throw is unhandled at the call site, taking down whatever adapter (webAuthn, tempoWallet, dangerous_secp256k1, etc.) was being set up.

Confirmed via runtime introspection in the affected environment:

typeof window                    // "object"
typeof window.dispatchEvent      // "undefined"  <-- crashes here
typeof window.addEventListener   // "undefined"
typeof CustomEvent               // "function"   (polyfilled)
typeof crypto.randomUUID         // "function"   (polyfilled)

Reproduction

  1. In any environment where window exists (possibly via global.window = global or similar) and CustomEvent/crypto.randomUUID are polyfilled, but window.dispatchEvent/addEventListener are not implemented (this is a natural state for React Native — there is no DOM, so nothing provides real event dispatching even when some other library or shim sets global.window).
  2. Call Provider.create({ adapter, ... }) for any adapter.
  3. Provider.create throws TypeError: undefined is not a function from inside announceProvider/window.dispatchEvent, rather than either skipping the (browser-only, EIP-6963-specific) announcement or throwing a clear error.

Expected behavior

The guard before calling announceProvider should also check that window.dispatchEvent (and ideally addEventListener) are actually functions, e.g.:

if (
  typeof window !== 'undefined' &&
  typeof window.dispatchEvent === 'function' &&
  typeof CustomEvent !== 'undefined' &&
  typeof crypto.randomUUID === 'function'
) { ... }

EIP-6963 injected-provider discovery is a browser-extension-wallet concept with no equivalent in non-browser environments; skipping the announcement there (rather than crashing) seems like the correct behavior regardless of which adapter is in use — this isn't specific to any one connector/adapter, since the check lives in the shared Provider.create() path.

Environment

  • accounts@0.15.2 (current latest) — confirmed the same guard is unchanged on main as of this issue.
  • Reached via a React Native (Expo) app where window is aliased to globalThis (a common RN pattern) and CustomEvent/crypto.randomUUID are polyfilled for unrelated reasons (WebAuthn/crypto needs), but no DOM event APIs exist.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions