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 →