# WalletConnect is broken on imd.fun and pool4.imd.fun: evidence report for @surfcoderepeat

**Date of investigation:** 2026-10-05 (UTC, about 10:25 to 10:35)
**Method:** read-only. I downloaded the public HTML and JS bundles of both sites, then made WebSocket handshakes to the WalletConnect relay (`wss://relay.walletconnect.org`) with each project ID, sending the site's `Origin` header. I logged in nowhere and changed nothing.

## TL;DR

Both claims in the request are **confirmed**, and the two sites fail for different reasons:

| Site | Project ID shipped in the bundle | Relay response from the site's origin | Root cause |
|---|---|---|---|
| https://imd.fun/ | `5b3bd5688d21f6be053d6c1c018e2ec8` (hard-coded fallback) | `{"code":3000,"message":"Unauthorized: origin not allowed"}` | The project exists, but its Reown/WalletConnect Cloud allowlist does not include `imd.fun` (or `www.imd.fun`, `explorer.imd.fun`, `pool4.imd.fun`). |
| https://pool4.imd.fun/ | `IMD_DEMO_PROJECT_ID` (literal placeholder string) | `{"code":3000,"message":"Project not found"}` | The placeholder was never replaced with a real project ID. |

**Fixes:**
- **imd.fun:** in the Reown dashboard, add `https://imd.fun` to the allowlist of project `5b3bd568…2ec8`. Also add `www.imd.fun` and `explorer.imd.fun` if they use wallet connections. No redeploy is needed.
- **pool4:** set a real project ID and redeploy. Its origin must be on that project's allowlist (`https://pool4.imd.fun`, or `*.imd.fun`).

## 1. Facts (directly observed, reproducible)

### 1.1 imd.fun

- **F1.** The imd.fun page chunk `/_next/static/chunks/app/page-39311abfceaabad0.js` (deployment `dpl_HYr36wGCk4tnM2TfVn5vJU993pga`, sha256 `0b9918ef…4ba8`) contains:
  ```js
  let a = i.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || "5b3bd5688d21f6be053d6c1c018e2ec8"
  ```
  The same constant is in `/token/`'s `page-ab9ac9690384fa9f.js`.
- **F2.** The lazy chunk `/_next/static/chunks/6023.17edcb64d7c8345a.js` (sha256 `d7162290…04d2`) passes that value to RainbowKit's `getDefaultConfig`:
  ```js
  (0,u.vX)({appName:"IMD",projectId:C.yh,chains:[b.u,h.R,x.o],wallets:[{groupName:"Popular",wallets:[…]}], …})
  ```
  `9551.057f1f18ac584e8a.js` contains the same config. The chains are Base, Ethereum mainnet and Robinhood chain, based on the RPC constants in the same module.
- **F3.** Relay handshakes with project `5b3bd5688d21f6be053d6c1c018e2ec8` gave these results. The tests ran twice, and the second run also included `relay.walletconnect.com`, with identical results.

  | `Origin` header | Relay reply |
  |---|---|
  | `https://imd.fun` | `Unauthorized: origin not allowed` (code 3000) |
  | `https://www.imd.fun` | `Unauthorized: origin not allowed` |
  | `https://explorer.imd.fun` | `Unauthorized: origin not allowed` |
  | `https://pool4.imd.fun` | `Unauthorized: origin not allowed` |
  | `https://example.com` (control) | `Unauthorized: origin not allowed` |
  | `http://localhost:3000` | connection accepted, no error frame within 4 s |
  | *(no Origin header)* | connection accepted, no error frame within 4 s |

- **F4.** Reown's relay docs say: *"Using `localhost` (or `127.0.0.1`) is always permitted, and if empty all origins are allowed."* Hostnames must match exactly, and wildcards are allowed per label. Source: https://docs.reown.com/cloud/relay

### 1.2 pool4.imd.fun

- **F5.** The pool4 chunk `/_next/static/immutable/chunks/00kadx1u3psjv.js` (sha256 `68627180…d01c`) contains:
  ```js
  C=(0,n.getDefaultConfig)({appName:"IMD",projectId:"IMD_DEMO_PROJECT_ID",chains:[k.CHAIN],transports:{…},ssr:!0})
  ```
- **F6.** The bundled RainbowKit only substitutes its own fallback ID when the value is exactly `"YOUR_PROJECT_ID"` (`return"YOUR_PROJECT_ID"===e&&(e="21fef48091f12692cad574a6f7753643")` in `1efog54gvgz4p.js`). So `IMD_DEMO_PROJECT_ID` is sent to the relay unchanged.
- **F7.** The relay answers `Project not found` (code 3000) for `IMD_DEMO_PROJECT_ID`, both from `https://pool4.imd.fun` and from `http://localhost:3000`. Reown's config API (`api.web3modal.org/appkit/v1/config`) returns **HTTP 403 Forbidden** for this ID, but HTTP 200 for `5b3bd568…`.
- **F8.** Vercel reported `age: 2130494` (about 24.7 days) on the cached pool4 HTML. That means the live pool4 build was deployed around 2026-09-10 or earlier and has not been rebuilt since.

### 1.3 Other observations made along the way

- **F9.** Both bundles embed Alchemy RPC URLs with API keys in client code. imd.fun uses `alch_sn3U…` as a fallback for both Base and mainnet, and pool4 uses `alch_kw7j…`. This is common practice for frontends and not a vulnerability by itself. It does mean the keys are public, so domain or rate restrictions on the Alchemy side are worth checking.

## 2. Inferences (reasoned from the facts, not directly observed)

- **I1 (high confidence).** In the live imd.fun build, the effective project ID is the fallback `5b3bd568…2ec8`. Next.js inlines `NEXT_PUBLIC_*` values at build time. If the env var had been set, the bundle would contain the literal value rather than the `env.X || "…"` expression (F1).
- **I2 (high confidence).** The project `5b3bd568…` exists and is active, since localhost is accepted (F3, F4). Its allowlist is **non-empty but lacks imd.fun**: an empty allowlist would accept every origin (F4), but `example.com` and all imd.fun hosts are rejected. Likely explanations: the project was set up for a different domain, or it is the default ID from a template/earlier project that was reused.
- **I3 (high confidence).** On imd.fun, the injected-wallet route (browser extension) probably still works, because it does not use the relay. QR-code and mobile-deep-link flows (WalletConnect proper) fail. In a real browser you would see a console error such as `Unauthorized: origin not allowed`.
- **I4 (high confidence).** On pool4, every WalletConnect-based flow fails with "Project not found". Injected wallets are probably unaffected.

## 3. Uncertainty and limits

- I did not drive a real browser or wallet. The failure is shown at the relay-protocol level by emulating the handshake the WalletConnect SDK makes, with an ed25519 `did:key` JWT and the `projectId` and `Origin` headers. The user-visible symptom is inferred from that, not screenshotted.
- I can't see the Reown dashboard, so the actual allowlist contents for `5b3bd568…` are unknown. I only know what it rejects and accepts.
- The relay's code 3000 messages (`Unauthorized: origin not allowed`, `Project not found`) are not listed in the Reown docs page I consulted. I report them verbatim as observed.
- Results reflect the deployments live on 2026-10-05. A redeploy or dashboard change after that date would change them.

## 4. Who to notify, and how (unanswered part of the request)

- **Who:** the request names @surfcoderepeat as the creator. A KuCoin blog post dated 2026-09-29 says: *"The journey of IMD began with Fren Pet … released on Base in August 2023 by developer Adam, known as @surfcoderepeat."* (https://www.kucoin.com/blog/vn-imd-token-community-owned-ai-agents). That is a **secondary source**. I found no creator attribution on imd.fun itself. The handle is an X/Twitter account (https://x.com/surfcoderepeat). There is no GitHub user with that name (GitHub API returned 404).
- **Contact channel:** none found on the sites. There is no `/.well-known/security.txt` (404), no repo link for the frontend, and no contact address.
- **Not done:** I did **not** send a message to @surfcoderepeat. Contacting a third party on a public platform is an outward-facing action that this task did not authorize, and I have no account to do it from. The draft below is ready for a human to send (X DM/reply, or the IMD community Discord).

### Draft message

> Hi @surfcoderepeat, heads-up: WalletConnect (QR/mobile) is broken on two IMD frontends, for different reasons. Checked 2026-10-05:
>
> 1. **imd.fun**: the bundle uses fallback projectId `5b3bd568…2ec8` (`NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID` isn't set at build). The relay rejects it from https://imd.fun with `3000 Unauthorized: origin not allowed` (localhost works, so the project is fine; the allowlist just doesn't include imd.fun). Fix: add `https://imd.fun` (plus www/explorer if needed) to that project's allowlist in the Reown dashboard. No redeploy needed.
> 2. **pool4.imd.fun**: `getDefaultConfig({ projectId: "IMD_DEMO_PROJECT_ID" })` is shipped literally, and the relay returns `3000 Project not found`. Fix: set a real project ID and redeploy, with pool4.imd.fun on its allowlist.
>
> Injected wallets (extensions) should still work on both. Full evidence: [link to this report]

## 5. How to reproduce

1. `curl -s https://pool4.imd.fun/_next/static/immutable/chunks/00kadx1u3psjv.js | grep -o 'projectId:"[^"]*"'` should print `projectId:"IMD_DEMO_PROJECT_ID"`.
2. `curl -s 'https://imd.fun/_next/static/chunks/app/page-39311abfceaabad0.js?dpl=dpl_HYr36wGCk4tnM2TfVn5vJU993pga' | grep -o 'WALLETCONNECT_PROJECT_ID||"[0-9a-f]*"'`
3. Open `https://imd.fun`, open DevTools, choose "Connect", then pick WalletConnect / QR. The console and network (WS) tabs show the relay error. Doing the same on pool4.imd.fun shows `Project not found`.
