WalletPair

Connect dApps to wallets.
No registration. No middleman. Just crypto.

Why WalletPair

Zero Registration

No API keys, project IDs, or accounts. Deploy a relay and start pairing.

End-to-End Encrypted

ChaCha20-Poly1305 AEAD. The relay routes only opaque bytes it cannot read.

Transport Agnostic

WebSocket, Bluetooth, local TCP — same protocol, same code.

Multi-Network

Chain-agnostic core with sub-protocols for EVM, Solana, Sui, and more via CAIP-2.

Formally Verified

ProVerif-proven under Dolev-Yao threat model. 7/7 security properties hold.

Self-Hostable

One Rust binary. No vendor lock-in. Your infrastructure, your rules.

How It Works

The dApp creates a channel, displays a QR code. The wallet scans it. After a cryptographic handshake with visual fingerprint verification, they communicate over an end-to-end encrypted session. The relay never sees your data.

protocol flow
 dApp                          Relay                         Wallet
  │                              │                              │
  │── create (pubkey) ──────────>│                              │
  │<─ ready.waiting ──────────── │                              │
  │                              │                              │
  │   ┌─────────────────────────────────────────────────────┐   │
  │   │  dApp displays QR code · wallet scans pairing URI   │   │
  │   └─────────────────────────────────────────────────────┘   │
  │                              │                              │
  │                              │ <──────── join (pubkey) ─────│
  │<─ join (pubkey, caps) ────── │                              │
  │                              │                              │
  │   ┌─────────────────────────────────────────────────────┐   │
  │   │  Both derive traffic keys · verify session fingerprint  │
  │   └─────────────────────────────────────────────────────┘   │
  │                              │                              │
  │── accept ───────────────────>│ ──── ready.connected ───────>│
  │<─ ready.connected ────────── │                              │
  │                              │                              │
  │── req (encrypted) ──────────>│ ──── req (encrypted) ───────>│
  │                              │ <─── res (encrypted) ────────│
  │<─ res (encrypted) ────────── │                              │

Start Integrating

For dApp Developers

  • Create a pairing URI and display it as a QR code
  • Send JSON-RPC requests over the encrypted channel
  • Wagmi connector and EIP-1193 provider included
import { DAppSession, WebSocketTransport } from 'walletpair-sdk';

const transport = new WebSocketTransport('wss://relay.walletpair.org/v1');
const session = new DAppSession({ transport, meta: { name: 'My dApp' } });

const uri = await session.createPairing();
// Display uri as QR code for wallet to scan

session.on('phase', async (phase) => {
  if (phase !== 'connected') return;
  const accounts = await session.request('wallet_getAccounts');
});
Read the dApp guide →

For Wallet Developers

  • Scan a pairing QR code and join the session
  • Handle incoming requests — approve or reject
  • Push events like accountsChanged and chainChanged
import { WalletSession, WebSocketTransport } from 'walletpair-sdk';

const transport = new WebSocketTransport('wss://relay.walletpair.org/v1');
const session = new WalletSession({
  transport,
  capabilities: {
    methods: ['wallet_getAccounts', 'wallet_signMessage'],
    events: ['accountsChanged', 'chainChanged'],
    chains: ['eip155:1', 'eip155:137'],
  },
});

await session.joinFromUri(pairingUri);

session.on('request', ({ id, method, params }) => {
  // Handle request and approve or reject
  session.approve(id, result);
});
Read the wallet guide →