Skip to content

Commit b515282

Browse files
Ubuntuclaude
andcommitted
feat: WalletConnect support via Reown AppKit + wagmi
The previous Connect Wallet flow used raw EIP-6963 discovery, which only sees browser-extension wallets (MetaMask, Rabby). Mobile wallets like MetaMask Mobile, Trust, Rainbow, Coinbase Wallet were invisible to the tool — blocking signers whose authorised keys live only on a phone. Adopt the same wallet stack tradingstrategy-ai/frontend already uses (@reown/appkit + @reown/appkit-adapter-wagmi + @wagmi/core + @wagmi/connectors) on top of the existing viem dependency. AppKit's modal handles browser extensions and WalletConnect-bridged mobile wallets in one UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent da3a3f6 commit b515282

10 files changed

Lines changed: 259 additions & 184 deletions

File tree

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# WalletConnect (Reown Cloud) project ID. Required for the AppKit modal to
2+
# pair desktop browsers with mobile wallets via QR. Get a free project ID at
3+
# https://cloud.reown.com.
4+
#
5+
# In CI/Pages deploys this is provided via the WALLET_CONNECT_PROJECT_ID
6+
# repository secret — see .github/workflows/deploy.yml.
7+
TS_PUBLIC_WALLET_CONNECT_PROJECT_ID=

.github/workflows/deploy.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ jobs:
4747
# so SvelteKit needs this as its base path. svelte.config.js
4848
# reads it via process.env.BASE_PATH.
4949
BASE_PATH: /open-multisig-hl
50+
# WalletConnect (Reown Cloud) project ID — baked into the static
51+
# bundle at build time so AppKit's mobile-wallet QR flow works.
52+
# Set as a repo secret: Settings → Secrets and variables → Actions.
53+
TS_PUBLIC_WALLET_CONNECT_PROJECT_ID: ${{ secrets.WALLET_CONNECT_PROJECT_ID }}
5054
run: pnpm run build
5155

5256
- name: Disable Jekyll

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog
2+
3+
## Unreleased
4+
5+
- Add WalletConnect support so signers can pair mobile wallets via QR (2026-04-27).

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ This application a web user interface for Hyperliquid native multisignature wall
2424

2525
# Run
2626

27-
To launch Open Hyperliquid Multisigner:
27+
Copy `.env.example` to `.env` and set `TS_PUBLIC_WALLET_CONNECT_PROJECT_ID` to a free project ID from [cloud.reown.com](https://cloud.reown.com). Without it the WalletConnect (mobile wallet) flow is disabled — desktop browser extensions still work.
2828

2929
```shell
30+
cp .env.example .env
31+
# edit .env
32+
pnpm install
3033
pnpm run dev
3134
```
3235

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@
3131
"dependencies": {
3232
"@lucide/svelte": "^1.8.0",
3333
"@msgpack/msgpack": "^3.1.3",
34+
"@reown/appkit": "^1.8.18",
35+
"@reown/appkit-adapter-wagmi": "^1.8.18",
3436
"@sveltejs/adapter-static": "^3.0.10",
37+
"@wagmi/connectors": "^5.11.2",
38+
"@wagmi/core": "^2.22.1",
3539
"viem": "^2.47.12"
3640
}
3741
}
Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
<!--
2+
@component
3+
Connect button + connected-account chip.
4+
5+
Opens AppKit's wallet picker modal on click. AppKit handles wallet discovery
6+
(browser extensions via EIP-6963 + WalletConnect-bridged mobile wallets via
7+
QR), so this component is intentionally tiny — the picker UI lives in AppKit.
8+
-->
19
<script lang="ts">
210
import { Button } from '$lib/components/ui/button/index.js';
311
import { getWallet } from '$lib/wallet.svelte.js';
@@ -19,44 +27,9 @@
1927
Disconnect
2028
</Button>
2129
{:else}
22-
<Button onclick={() => wallet.connect()} disabled={wallet.connecting}>
23-
{wallet.connecting ? 'Connecting...' : 'Connect Wallet'}
24-
</Button>
30+
<Button onclick={() => wallet.connect()}>Connect wallet</Button>
2531
{/if}
2632
{#if wallet.error}
2733
<span class="text-destructive text-xs">{wallet.error}</span>
2834
{/if}
2935
</div>
30-
31-
<!-- Wallet picker modal -->
32-
{#if wallet.showPicker}
33-
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
34-
<div
35-
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
36-
onclick={() => (wallet.showPicker = false)}
37-
>
38-
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
39-
<div
40-
class="bg-background w-80 rounded-xl border p-6 shadow-xl"
41-
onclick={(e) => e.stopPropagation()}
42-
>
43-
<h2 class="mb-4 text-base font-semibold">Select a wallet</h2>
44-
<ul class="space-y-2">
45-
{#each wallet.discoveredWallets as w}
46-
<li>
47-
<button
48-
class="hover:bg-muted flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors"
49-
onclick={() => wallet.connectProvider(w)}
50-
>
51-
<img src={w.info.icon} alt={w.info.name} class="size-8 rounded-md" />
52-
<span class="text-sm font-medium">{w.info.name}</span>
53-
</button>
54-
</li>
55-
{/each}
56-
</ul>
57-
<Button variant="ghost" size="sm" class="mt-4 w-full" onclick={() => (wallet.showPicker = false)}>
58-
Cancel
59-
</Button>
60-
</div>
61-
</div>
62-
{/if}

src/lib/config.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Public runtime configuration.
3+
*
4+
* Values are read from SvelteKit's `$env/static/public`, which means they are
5+
* baked into the static bundle at build time. Set them via `.env` for local
6+
* development or as repository secrets in the deploy workflow.
7+
*
8+
* Per project convention (see CLAUDE.md), client-accessible env vars use the
9+
* `TS_PUBLIC_` prefix — configured in `svelte.config.js` via `kit.env.publicPrefix`.
10+
*/
11+
12+
import { env } from '$env/dynamic/public'
13+
14+
/**
15+
* WalletConnect (Reown Cloud) project credentials.
16+
*
17+
* The project ID identifies this dapp to the WalletConnect relay network so
18+
* mobile wallets can pair with the desktop UI via QR code. Get a free project
19+
* ID at https://cloud.reown.com.
20+
*
21+
* If unset, AppKit still loads but mobile-wallet pairing will be disabled —
22+
* a console warning is emitted to surface the misconfiguration.
23+
*/
24+
export const walletConnectConfig = (() => {
25+
const projectId = env.TS_PUBLIC_WALLET_CONNECT_PROJECT_ID ?? ''
26+
if (!projectId && typeof window !== 'undefined') {
27+
console.warn(
28+
'TS_PUBLIC_WALLET_CONNECT_PROJECT_ID is not set — WalletConnect (mobile wallet support) will be disabled. ' +
29+
'Set it in .env (local) or as a repo secret (deploy workflow).',
30+
)
31+
}
32+
return { projectId }
33+
})()

0 commit comments

Comments
 (0)