2026-03-18 16:13:38 +01:00
|
|
|
# React integration
|
|
|
|
|
|
|
|
|
|
`@wizardconnect/react` provides React components and hooks for dapp developers who want to add
|
|
|
|
|
WizardConnect wallet connectivity without writing relay boilerplate.
|
|
|
|
|
|
|
|
|
|
## Quick start
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
import { useWizardConnect, WizardConnectQRDialog } from "@wizardconnect/react";
|
|
|
|
|
|
|
|
|
|
function App() {
|
|
|
|
|
const wc = useWizardConnect({ dappName: "My Dapp" });
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<button onClick={wc.connect} disabled={wc.state !== "idle"}>
|
|
|
|
|
Connect Wallet
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
{wc.uri && wc.qrUri && (
|
|
|
|
|
<WizardConnectQRDialog
|
|
|
|
|
show={wc.state === "connecting"}
|
|
|
|
|
onClose={() => wc.disconnect()}
|
|
|
|
|
uri={wc.uri}
|
|
|
|
|
qrUri={wc.qrUri}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{wc.state === "connected" && (
|
|
|
|
|
<p>Connected to {wc.walletName}</p>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## useWizardConnect
|
|
|
|
|
|
|
|
|
|
The `useWizardConnect` hook manages the full relay lifecycle:
|
|
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
1. **`connect()`** — calls `initiateDappRelay()`, creates a `DappConnectionManager`, sets
|
|
|
|
|
`uri`/`qrUri` for QR display, and transitions to `"connecting"`.
|
|
|
|
|
2. **Key exchange** — persists the wallet's public key to session storage.
|
|
|
|
|
3. **`walletready`** — transitions to `"connected"` and populates `walletName`/`walletIcon`.
|
|
|
|
|
4. **Auto-reconnect** — on mount, checks session storage for a stored session with a
|
|
|
|
|
`walletPublicKey` and automatically reconnects. During auto-reconnect, `uri`/`qrUri` remain
|
|
|
|
|
`null` (no QR code to display — credentials are already known).
|
2026-03-18 16:13:38 +01:00
|
|
|
5. **`disconnect()`** — sends a courtesy disconnect, cleans up the relay, and clears session storage.
|
2026-04-03 17:11:18 +02:00
|
|
|
6. **Remote disconnect** — when the wallet sends a disconnect, the hook transitions to
|
|
|
|
|
`"disconnected"`, clears the session, and tears down the relay.
|
2026-03-18 16:13:38 +01:00
|
|
|
|
|
|
|
|
### Return value
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
interface UseWizardConnectResult {
|
|
|
|
|
state: "idle" | "connecting" | "connected" | "disconnected";
|
|
|
|
|
manager: DappConnectionManager | null;
|
|
|
|
|
uri: string | null;
|
|
|
|
|
qrUri: string | null;
|
|
|
|
|
walletName: string | null;
|
|
|
|
|
walletIcon: string | null;
|
|
|
|
|
connect: () => boolean;
|
|
|
|
|
disconnect: () => Promise<void>;
|
|
|
|
|
error: string | null;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Using the manager
|
|
|
|
|
|
|
|
|
|
Once `state === "connected"`, the `manager` is a live `DappConnectionManager` from
|
|
|
|
|
`@wizardconnect/dapp`. Use it to derive addresses and request signatures:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Derive a receive address pubkey
|
|
|
|
|
const pubkey = wc.manager.getPubkey(0, 0n);
|
|
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
// Send a sign request (auto-fills action, sequence, time)
|
|
|
|
|
const response = await wc.manager.signTransaction({
|
|
|
|
|
transaction: { transaction: txHex, sourceOutputs, broadcast: true },
|
|
|
|
|
inputPaths: [[0, "receive", 0]],
|
|
|
|
|
});
|
2026-03-18 16:13:38 +01:00
|
|
|
```
|
|
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
See the [dapp integration docs](dapp.md#sending-a-sign-request) for cancellation via
|
|
|
|
|
`AbortSignal` and the low-level `sendSignRequest` API.
|
|
|
|
|
|
2026-03-18 16:13:38 +01:00
|
|
|
For most dapps, you'll wrap the manager in an app-specific wallet adapter (like
|
|
|
|
|
`RelayWalletDapp` in the Cauldron and Moria codebases).
|
|
|
|
|
|
|
|
|
|
## WizardConnectQRDialog
|
|
|
|
|
|
|
|
|
|
A framework-independent modal dialog for displaying the connection QR code. Uses inline styles
|
|
|
|
|
(no Tailwind or CSS framework dependency) with a dark theme by default.
|
|
|
|
|
|
|
|
|
|
### Customization
|
|
|
|
|
|
|
|
|
|
Colors, text, and logos are all customizable via props:
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
<WizardConnectQRDialog
|
|
|
|
|
show={true}
|
|
|
|
|
onClose={handleClose}
|
|
|
|
|
uri={connection.uri}
|
|
|
|
|
qrUri={connection.qrUri}
|
|
|
|
|
title="My Protocol"
|
|
|
|
|
subtitle="Scan to pair your wallet"
|
|
|
|
|
logoUrl="/my-logo.png"
|
|
|
|
|
theme={{
|
|
|
|
|
dialogBackground: "#0f172a",
|
|
|
|
|
headerBackground: "#0f172a",
|
|
|
|
|
borderColor: "#334155",
|
|
|
|
|
}}
|
|
|
|
|
onCopy={(uri) => {
|
|
|
|
|
navigator.clipboard.writeText(uri);
|
|
|
|
|
showToast("Copied!");
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `onCopy` callback replaces the default `navigator.clipboard.writeText` behavior, which is
|
|
|
|
|
useful when the dapp has its own toast/notification system.
|
|
|
|
|
|
|
|
|
|
## AlphanumericQRCode
|
|
|
|
|
|
|
|
|
|
A standalone canvas-based QR code component. Uses QR Alphanumeric mode with error correction
|
|
|
|
|
level H (30% recovery), which allows a center logo overlay without breaking the code.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
<AlphanumericQRCode
|
|
|
|
|
value="WIZ://..."
|
|
|
|
|
size={280}
|
|
|
|
|
foreground="#1e2a4a"
|
|
|
|
|
background="#ffffff"
|
|
|
|
|
logoUrl="/logo.png"
|
|
|
|
|
/>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Session persistence
|
|
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
By default, `useWizardConnect` persists session data to localStorage under the
|
|
|
|
|
`wizardconnect-session` key. The stored session includes:
|
|
|
|
|
|
|
|
|
|
- **Relay credentials** (`privateKey`, `secret`) — saved on `connect()`
|
|
|
|
|
- **Wallet public key** (`walletPublicKey`) — saved after key exchange
|
|
|
|
|
- **Wallet identity** (`walletName`, `walletIcon`) — saved on `walletready`
|
|
|
|
|
- **Xpub paths** (`paths`) — saved on `walletready`
|
|
|
|
|
|
|
|
|
|
On page refresh, the hook auto-reconnects if a stored session with `walletPublicKey` exists.
|
|
|
|
|
Xpub paths and wallet name are restored immediately so `getPubkey()` works and the UI can
|
|
|
|
|
display the wallet name before the wallet app responds. During auto-reconnect, `uri` and
|
|
|
|
|
`qrUri` remain `null` — the QR dialog should not be shown. The typical pattern is:
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
{wc.uri && wc.qrUri && (
|
|
|
|
|
<WizardConnectQRDialog
|
|
|
|
|
show={wc.state === "connecting"}
|
|
|
|
|
onClose={() => wc.disconnect()}
|
|
|
|
|
uri={wc.uri}
|
|
|
|
|
qrUri={wc.qrUri}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
```
|
2026-03-22 21:04:14 +01:00
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
This naturally hides the dialog during auto-reconnect since `wc.uri` is `null`.
|
2026-03-18 16:13:38 +01:00
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
If the wallet sends a disconnect, the hook clears the session automatically and transitions
|
|
|
|
|
to `"disconnected"`. Dapps should listen for this state change to update their UI (e.g.
|
|
|
|
|
clear the wallet from their store).
|
|
|
|
|
|
|
|
|
|
### Customization
|
2026-03-18 16:13:38 +01:00
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
useWizardConnect({
|
2026-04-03 17:11:18 +02:00
|
|
|
sessionKey: "my-app-session", // custom storage key (default: "wizardconnect-session")
|
|
|
|
|
persistSession: false, // disable persistence entirely
|
|
|
|
|
storage: myCustomStorage, // custom SessionStorage backend (default: localStorage)
|
2026-03-18 16:13:38 +01:00
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-03 17:11:18 +02:00
|
|
|
The `storage` option accepts any object with `getItem`, `setItem`, and `removeItem` methods
|
|
|
|
|
(the standard Web Storage API). This is useful for React Native or server-side rendering
|
|
|
|
|
where `localStorage` is not available.
|
|
|
|
|
|
|
|
|
|
On disconnect, the stored session is cleared.
|