fix(web): offer mobile EVM wallets when window.ethereum is missing #32

Merged
PlasticDigits merged 2 commits from fix/15-evm-mobile-wallets into main 2026-08-30 17:41:15 +00:00
PlasticDigits commented 2026-08-30 16:01:42 +00:00 (Migrated from gitlab.com)

Summary

  • /sign/evm no longer dead-ends on No EVM wallet found (install MetaMask or similar) when Safari/Chrome/Firefox have no injected EIP-1193 provider (GitLab #15).
  • Discover wallets via EIP-6963, ethereum.providers[], window.ethereum, and window.BinanceChain (with a short wait for late MetaMask iOS / Binance WebView inject). Several providers require an explicit pick.
  • Missing-provider path: Open in MetaMask (documented https://link.metamask.io/dapp/…), Open in Binance Web3, Copy link (portal URL, query intact). In-page WalletConnect personal_sign when Legal-owned VITE_WC_PROJECT_ID is set (hidden when unset).
  • account=0x… continuity: a different connected address is a hard fail. API EIP-191 verify is unchanged. Terra/Solana/Telegram pages are unchanged (EVM still has no Open in Keplr).

Closes #15

Test plan

  • cd web && npx vitest run — 102 passed (provider discovery, deeplink allowlist, claimed-account, WC pairing, signShell busy reset)
  • Playwright evm-sign + sign-pages + terra-sign + redirect — 24 passed with 5 workers (fullyParallel), then retest
  • Manual: iOS Safari (no inject) against staging/prod for a test property — no dead-end; Open in MetaMask and/or WalletConnect completes signed_latest: true
  • Manual: MetaMask iOS in-app browser — Connect & sign succeeds (injected / EIP-6963)
  • Manual: Binance Web3 in-app browser — Connect & sign succeeds
  • Manual: desktop MetaMask extension still signs
  • Confirm VITE_WC_PROJECT_ID is set on the Legal portal build if in-page WC should appear in production

Acceptance criteria

  • Mobile Safari/Chrome: /sign/evm?property=… never dead-ends on install-MetaMask without a next step (Open in MetaMask / Open in Binance Web3 / Copy link / WC)
  • Happy path A (mocked): EIP-6963 announce with no window.ethereum → signed_latest
  • Happy path B (mocked): window.BinanceChain only → signed_latest
  • Happy path C (mocked): WalletConnect hook in system-browser style → signed_latest
  • Desktop injected window.ethereum path still works (evm-sign regression)
  • Consent gate still blocks wallet request until terms are scrolled and the checkbox is checked
  • Claimed account=0x… mismatch fails closed (no signed_latest for the claimed account)
  • Terra / Solana / Telegram unchanged (EVM has no Open in Keplr)
  • Copy is retail-short (no EIP-191 / EIP-6963 in idle status)
  • skills/portal-sign-disclosure/SKILL.md and signShell.ts comments no longer say EVM must omit extraControls
  • API still rejects wrong recovered address / property / hash / timestamp / oversized body — unchanged api/src/verify/evm.rs; not re-run in this MR (existing CI test:rust)
  • Real MetaMask iOS / Binance Web3 / iOS Safari — manual, not in CI (Chromium mocks only, GitLab #4)

Invariants / docs

## Summary - `/sign/evm` no longer dead-ends on `No EVM wallet found (install MetaMask or similar)` when Safari/Chrome/Firefox have no injected EIP-1193 provider (GitLab #15). - Discover wallets via EIP-6963, `ethereum.providers[]`, `window.ethereum`, and `window.BinanceChain` (with a short wait for late MetaMask iOS / Binance WebView inject). Several providers require an explicit pick. - Missing-provider path: **Open in MetaMask** (documented `https://link.metamask.io/dapp/…`), **Open in Binance Web3**, **Copy link** (portal URL, query intact). In-page WalletConnect `personal_sign` when Legal-owned `VITE_WC_PROJECT_ID` is set (hidden when unset). - `account=0x…` continuity: a different connected address is a hard fail. API EIP-191 verify is unchanged. Terra/Solana/Telegram pages are unchanged (EVM still has no Open in Keplr). Closes #15 ## Test plan - [x] `cd web && npx vitest run` — 102 passed (provider discovery, deeplink allowlist, claimed-account, WC pairing, signShell busy reset) - [x] Playwright `evm-sign` + `sign-pages` + `terra-sign` + `redirect` — 24 passed with 5 workers (`fullyParallel`), then retest - [ ] Manual: iOS Safari (no inject) against staging/prod for a **test property** — no dead-end; Open in MetaMask and/or WalletConnect completes `signed_latest: true` - [ ] Manual: MetaMask iOS in-app browser — Connect & sign succeeds (injected / EIP-6963) - [ ] Manual: Binance Web3 in-app browser — Connect & sign succeeds - [ ] Manual: desktop MetaMask extension still signs - [ ] Confirm `VITE_WC_PROJECT_ID` is set on the Legal portal build if in-page WC should appear in production ## Acceptance criteria - [x] Mobile Safari/Chrome: `/sign/evm?property=…` never dead-ends on install-MetaMask without a next step (Open in MetaMask / Open in Binance Web3 / Copy link / WC) - [x] Happy path A (mocked): EIP-6963 announce with **no** `window.ethereum` → `signed_latest` - [x] Happy path B (mocked): `window.BinanceChain` only → `signed_latest` - [x] Happy path C (mocked): WalletConnect hook in system-browser style → `signed_latest` - [x] Desktop injected `window.ethereum` path still works (`evm-sign` regression) - [x] Consent gate still blocks wallet `request` until terms are scrolled and the checkbox is checked - [x] Claimed `account=0x…` mismatch fails closed (no `signed_latest` for the claimed account) - [x] Terra / Solana / Telegram unchanged (EVM has no Open in Keplr) - [x] Copy is retail-short (no EIP-191 / EIP-6963 in idle status) - [x] `skills/portal-sign-disclosure/SKILL.md` and `signShell.ts` comments no longer say EVM must omit extraControls - [ ] API still rejects wrong recovered address / property / hash / timestamp / oversized body — **unchanged** `api/src/verify/evm.rs`; not re-run in this MR (existing CI `test:rust`) - [ ] Real MetaMask iOS / Binance Web3 / iOS Safari — **manual**, not in CI (Chromium mocks only, GitLab #4) ## Invariants / docs - [`skills/portal-sign-disclosure/SKILL.md`](../blob/fix/15-evm-mobile-wallets/skills/portal-sign-disclosure/SKILL.md) — EVM extraControls, deeplink origin bind, WC, account continuity - [`skills/testing-coverage/SKILL.md`](../blob/fix/15-evm-mobile-wallets/skills/testing-coverage/SKILL.md) — EVM mobile artifacts - [`skills/terra-classic-adr036/SKILL.md`](../blob/fix/15-evm-mobile-wallets/skills/terra-classic-adr036/SKILL.md) — do not mount Terra CTAs on EVM - [`README.md`](../blob/fix/15-evm-mobile-wallets/README.md) EVM section + `web/.env.example` (`VITE_WC_PROJECT_ID` also gates EVM WC) - [`packages/cl8y-clickwrap/README.md`](../blob/fix/15-evm-mobile-wallets/packages/cl8y-clickwrap/README.md) — integrators still redirect to `sign_urls.evm`; pass `account`
PlasticDigits commented 2026-08-30 16:04:53 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-08-30 16:04:55 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 78048288 - test(web): stabilize EVM mobile e2e and ignore Connect clicks while busy

Compare with previous version

added 1 commit <ul><li>78048288 - test(web): stabilize EVM mobile e2e and ignore Connect clicks while busy</li></ul> [Compare with previous version](/PlasticDigits/cl8y-ecosystem-legal/-/merge_requests/14/diffs?diff_id=1992760016&start_sha=e455f1a9d85d8ffc7b4fc8a75ed88fcc496f5475)
PlasticDigits commented 2026-08-30 17:41:15 +00:00 (Migrated from gitlab.com)

mentioned in commit 72c45a73d5

mentioned in commit 72c45a73d559efadb0969224e8b420a20e43e55b
PlasticDigits (Migrated from gitlab.com) merged commit 72c45a73d5 into main 2026-08-30 17:41:15 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-ecosystem-legal!32
No description provided.